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> 88 #include <pcl/io/pcd_io.h> 89 #include <pcl/io/ply_io.h> 90 #include <pcl/io/obj_io.h> 91 #include <pcl/filters/voxel_grid.h> 92 #include <pcl/filters/crop_box.h> 93 #include <pcl/common/transforms.h> 94 #include <pcl/common/common.h> 96 #ifdef RTABMAP_OCTOMAP 107 editDepthDialog_(new QDialog(this)),
108 editMapDialog_(new QDialog(this)),
109 savedMaximized_(
false),
112 infoReducedGraph_(
false),
123 ui_ =
new Ui_DatabaseViewer();
125 ui_->buttonBox->setVisible(
false);
126 connect(
ui_->buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(close()));
128 ui_->comboBox_logger_level->setVisible(parent==0);
129 ui_->label_logger_level->setVisible(parent==0);
130 connect(
ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
updateLoggerLevel()));
131 connect(
ui_->actionVertical_Layout, SIGNAL(toggled(
bool)),
this, SLOT(
setupMainLayout(
bool)));
136 vLayout->setContentsMargins(0,0,0,0);
137 vLayout->setSpacing(0);
139 QDialogButtonBox * buttonBox =
new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal,
editDepthDialog_);
140 vLayout->addWidget(buttonBox);
143 connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
editDepthArea_, SLOT(resetChanges()));
150 vLayout->setContentsMargins(0,0,0,0);
151 vLayout->setSpacing(0);
153 buttonBox =
new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal,
editMapDialog_);
154 vLayout->addWidget(buttonBox);
155 connect(buttonBox, SIGNAL(accepted()),
editMapDialog_, SLOT(accept()));
156 connect(buttonBox, SIGNAL(rejected()),
editMapDialog_, SLOT(reject()));
157 connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
editMapArea_, SLOT(resetChanges()));
161 QString title(
"RTAB-Map Database Viewer[*]");
162 this->setWindowTitle(title);
164 ui_->dockWidget_constraints->setVisible(
false);
165 ui_->dockWidget_graphView->setVisible(
false);
166 ui_->dockWidget_occupancyGridView->setVisible(
false);
167 ui_->dockWidget_guiparameters->setVisible(
false);
168 ui_->dockWidget_coreparameters->setVisible(
false);
169 ui_->dockWidget_info->setVisible(
false);
170 ui_->dockWidget_stereoView->setVisible(
false);
171 ui_->dockWidget_view3d->setVisible(
false);
172 ui_->dockWidget_statistics->setVisible(
false);
192 ui_->graphicsView_stereo->setAlpha(255);
194 #ifndef RTABMAP_OCTOMAP 195 ui_->checkBox_octomap->setEnabled(
false);
196 ui_->checkBox_octomap->setChecked(
false);
227 ui_->parameters_toolbox->setupUi(parameters);
233 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
234 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
235 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
236 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
237 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
238 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
240 ui_->menuView->addAction(
ui_->dockWidget_constraints->toggleViewAction());
241 ui_->menuView->addAction(
ui_->dockWidget_graphView->toggleViewAction());
242 ui_->menuView->addAction(
ui_->dockWidget_occupancyGridView->toggleViewAction());
243 ui_->menuView->addAction(
ui_->dockWidget_stereoView->toggleViewAction());
244 ui_->menuView->addAction(
ui_->dockWidget_view3d->toggleViewAction());
245 ui_->menuView->addAction(
ui_->dockWidget_guiparameters->toggleViewAction());
246 ui_->menuView->addAction(
ui_->dockWidget_coreparameters->toggleViewAction());
247 ui_->menuView->addAction(
ui_->dockWidget_info->toggleViewAction());
248 ui_->menuView->addAction(
ui_->dockWidget_statistics->toggleViewAction());
249 connect(
ui_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateGraphView()));
250 connect(
ui_->dockWidget_occupancyGridView->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateGraphView()));
251 connect(
ui_->dockWidget_statistics->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateStatistics()));
252 connect(
ui_->dockWidget_info->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateInfo()));
255 connect(
ui_->parameters_toolbox, SIGNAL(parametersChanged(
const QStringList &)),
this, SLOT(
notifyParametersChanged(
const QStringList &)));
257 connect(
ui_->actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
259 ui_->actionOpen_database->setEnabled(
true);
260 ui_->actionClose_database->setEnabled(
false);
263 ui_->actionSave_config->setShortcut(QKeySequence::Save);
264 connect(
ui_->actionSave_config, SIGNAL(triggered()),
this, SLOT(
writeSettings()));
265 connect(
ui_->actionOpen_database, SIGNAL(triggered()),
this, SLOT(
openDatabase()));
266 connect(
ui_->actionClose_database, SIGNAL(triggered()),
this, SLOT(
closeDatabase()));
267 connect(
ui_->actionDatabase_recovery, SIGNAL(triggered()),
this, SLOT(
recoverDatabase()));
269 connect(
ui_->actionExtract_images, SIGNAL(triggered()),
this, SLOT(
extractImages()));
270 connect(
ui_->actionEdit_depth_image, SIGNAL(triggered()),
this, SLOT(
editDepthImage()));
271 connect(
ui_->actionGenerate_graph_dot, SIGNAL(triggered()),
this, SLOT(
generateGraph()));
273 connect(
ui_->actionRaw_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesRaw()));
276 connect(
ui_->actionKITTI_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesKITTI()));
279 connect(
ui_->actionPoses_KML, SIGNAL(triggered()),
this , SLOT(
exportPosesKML()));
280 connect(
ui_->actionGPS_TXT, SIGNAL(triggered()),
this , SLOT(
exportGPS_TXT()));
281 connect(
ui_->actionGPS_KML, SIGNAL(triggered()),
this , SLOT(
exportGPS_KML()));
282 connect(
ui_->actionEdit_optimized_2D_map, SIGNAL(triggered()),
this , SLOT(
editSaved2DMap()));
283 connect(
ui_->actionExport_saved_2D_map, SIGNAL(triggered()),
this , SLOT(
exportSaved2DMap()));
284 connect(
ui_->actionImport_2D_map, SIGNAL(triggered()),
this , SLOT(
import2DMap()));
285 connect(
ui_->actionRegenerate_optimized_2D_map, SIGNAL(triggered()),
this , SLOT(
regenerateSavedMap()));
289 connect(
ui_->actionView_3D_map, SIGNAL(triggered()),
this, SLOT(
view3DMap()));
290 connect(
ui_->actionGenerate_3D_map_pcd, SIGNAL(triggered()),
this, SLOT(
generate3DMap()));
298 connect(
ui_->actionReset_all_changes, SIGNAL(triggered()),
this, SLOT(
resetAllChanges()));
303 connect(
ui_->pushButton_add, SIGNAL(clicked()),
this, SLOT(
addConstraint()));
306 ui_->pushButton_refine->setEnabled(
false);
307 ui_->pushButton_add->setEnabled(
false);
308 ui_->pushButton_reset->setEnabled(
false);
309 ui_->pushButton_reject->setEnabled(
false);
311 ui_->menuEdit->setEnabled(
false);
312 ui_->actionGenerate_3D_map_pcd->setEnabled(
false);
313 ui_->actionExport->setEnabled(
false);
314 ui_->actionExtract_images->setEnabled(
false);
315 ui_->menuExport_poses->setEnabled(
false);
316 ui_->menuExport_GPS->setEnabled(
false);
317 ui_->actionPoses_KML->setEnabled(
false);
318 ui_->actionEdit_optimized_2D_map->setEnabled(
false);
319 ui_->actionExport_saved_2D_map->setEnabled(
false);
320 ui_->actionImport_2D_map->setEnabled(
false);
321 ui_->actionRegenerate_optimized_2D_map->setEnabled(
false);
322 ui_->actionView_optimized_mesh->setEnabled(
false);
323 ui_->actionExport_optimized_mesh->setEnabled(
false);
324 ui_->actionUpdate_optimized_mesh->setEnabled(
false);
326 ui_->horizontalSlider_A->setTracking(
false);
327 ui_->horizontalSlider_B->setTracking(
false);
328 ui_->horizontalSlider_A->setEnabled(
false);
329 ui_->horizontalSlider_B->setEnabled(
false);
332 connect(
ui_->horizontalSlider_A, SIGNAL(sliderMoved(
int)),
this, SLOT(
sliderAMoved(
int)));
333 connect(
ui_->horizontalSlider_B, SIGNAL(sliderMoved(
int)),
this, SLOT(
sliderBMoved(
int)));
335 connect(
ui_->spinBox_mesh_angleTolerance, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
336 connect(
ui_->spinBox_mesh_minClusterSize, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
337 connect(
ui_->spinBox_mesh_fillDepthHoles, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
338 connect(
ui_->spinBox_mesh_depthError, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
339 connect(
ui_->checkBox_mesh_quad, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
340 connect(
ui_->spinBox_mesh_triangleSize, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
341 connect(
ui_->checkBox_showWords, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
342 connect(
ui_->checkBox_showCloud, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
343 connect(
ui_->checkBox_showMesh, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
344 connect(
ui_->checkBox_showScan, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
345 connect(
ui_->checkBox_showMap, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
346 connect(
ui_->checkBox_showGrid, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
347 connect(
ui_->checkBox_odomFrame_3dview, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
349 ui_->horizontalSlider_neighbors->setTracking(
false);
350 ui_->horizontalSlider_loops->setTracking(
false);
351 ui_->horizontalSlider_neighbors->setEnabled(
false);
352 ui_->horizontalSlider_loops->setEnabled(
false);
362 ui_->checkBox_showOptimized->setEnabled(
false);
363 connect(
ui_->toolButton_constraint, SIGNAL(clicked(
bool)),
this, SLOT(
editConstraint()));
366 ui_->horizontalSlider_iterations->setTracking(
false);
367 ui_->horizontalSlider_iterations->setEnabled(
false);
368 ui_->spinBox_optimizationsFrom->setEnabled(
false);
371 connect(
ui_->spinBox_optimizationsFrom, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
372 connect(
ui_->checkBox_iterativeOptimization, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
373 connect(
ui_->checkBox_spanAllMaps, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
374 connect(
ui_->checkBox_wmState, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
375 connect(
ui_->graphViewer, SIGNAL(mapShownRequested()),
this, SLOT(
updateGraphView()));
376 connect(
ui_->checkBox_ignorePoseCorrection, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
378 connect(
ui_->checkBox_ignoreGlobalLoop, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
379 connect(
ui_->checkBox_ignoreLocalLoopSpace, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
380 connect(
ui_->checkBox_ignoreLocalLoopTime, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
381 connect(
ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
382 connect(
ui_->checkBox_ignoreLandmarks, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
383 connect(
ui_->doubleSpinBox_optimizationScale, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
384 connect(
ui_->checkBox_octomap, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
385 connect(
ui_->checkBox_grid_2d, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
386 connect(
ui_->comboBox_octomap_rendering_type, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
updateOctomapView()));
388 connect(
ui_->checkBox_grid_empty, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
389 connect(
ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
updateConstraintView()));
391 connect(
ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(
double)),
this, SLOT(
update3dView()));
393 connect(
ui_->spinBox_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
394 connect(
ui_->groupBox_posefiltering, SIGNAL(clicked(
bool)),
this, SLOT(
updateGraphView()));
395 connect(
ui_->doubleSpinBox_posefilteringRadius, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
396 connect(
ui_->doubleSpinBox_posefilteringAngle, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
398 ui_->label_stereo_inliers_name->setStyleSheet(
"QLabel {color : blue; }");
399 ui_->label_stereo_flowOutliers_name->setStyleSheet(
"QLabel {color : red; }");
400 ui_->label_stereo_slopeOutliers_name->setStyleSheet(
"QLabel {color : yellow; }");
401 ui_->label_stereo_disparityOutliers_name->setStyleSheet(
"QLabel {color : magenta; }");
405 connect(
ui_->graphViewer, SIGNAL(configChanged()),
this, SLOT(
configModified()));
406 connect(
ui_->graphicsView_A, SIGNAL(configChanged()),
this, SLOT(
configModified()));
407 connect(
ui_->graphicsView_B, SIGNAL(configChanged()),
this, SLOT(
configModified()));
408 connect(
ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
configModified()));
409 connect(
ui_->actionVertical_Layout, SIGNAL(toggled(
bool)),
this, SLOT(
configModified()));
410 connect(
ui_->checkBox_alignPosesWithGroundTruth, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
411 connect(
ui_->checkBox_alignScansCloudsWithGroundTruth, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
412 connect(
ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
413 connect(
ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
414 connect(
ui_->checkBox_timeStats, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
415 connect(
ui_->checkBox_timeStats, SIGNAL(stateChanged(
int)),
this, SLOT(
updateStatistics()));
417 connect(
ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
418 connect(
ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
419 connect(
ui_->spinBox_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
420 connect(
ui_->groupBox_posefiltering, SIGNAL(clicked(
bool)),
this, SLOT(
configModified()));
421 connect(
ui_->doubleSpinBox_posefilteringRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
422 connect(
ui_->doubleSpinBox_posefilteringAngle, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
424 connect(
ui_->spinBox_icp_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
425 connect(
ui_->doubleSpinBox_icp_maxDepth, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
426 connect(
ui_->doubleSpinBox_icp_minDepth, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
427 connect(
ui_->checkBox_icp_from_depth, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
429 connect(
ui_->doubleSpinBox_detectMore_radius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
430 connect(
ui_->doubleSpinBox_detectMore_angle, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
431 connect(
ui_->spinBox_detectMore_iterations, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
432 connect(
ui_->checkBox_detectMore_intraSession, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
433 connect(
ui_->checkBox_detectMore_interSession, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
435 connect(
ui_->lineEdit_obstacleColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
436 connect(
ui_->lineEdit_groundColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
437 connect(
ui_->lineEdit_emptyColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
438 connect(
ui_->lineEdit_obstacleColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
439 connect(
ui_->lineEdit_groundColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
440 connect(
ui_->lineEdit_emptyColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
443 connect(
ui_->toolButton_emptyColor, SIGNAL(clicked(
bool)),
this, SLOT(
selectEmptyColor()));
444 connect(
ui_->spinBox_cropRadius, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
449 QList<QDockWidget*> dockWidgets = this->findChildren<QDockWidget*>();
450 for(
int i=0; i<dockWidgets.size(); ++i)
452 connect(dockWidgets[i], SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
this, SLOT(
configModified()));
453 connect(dockWidgets[i]->toggleViewAction(), SIGNAL(toggled(
bool)),
this, SLOT(
configModified()));
455 ui_->dockWidget_constraints->installEventFilter(
this);
456 ui_->dockWidget_graphView->installEventFilter(
this);
457 ui_->dockWidget_occupancyGridView->installEventFilter(
this);
458 ui_->dockWidget_stereoView->installEventFilter(
this);
459 ui_->dockWidget_view3d->installEventFilter(
this);
460 ui_->dockWidget_guiparameters->installEventFilter(
this);
461 ui_->dockWidget_coreparameters->installEventFilter(
this);
462 ui_->dockWidget_info->installEventFilter(
this);
463 ui_->dockWidget_statistics->installEventFilter(
this);
470 #ifdef RTABMAP_OCTOMAP 479 qobject_cast<QHBoxLayout *>(
ui_->horizontalLayout_imageViews->layout())->setDirection(QBoxLayout::TopToBottom);
483 qobject_cast<QHBoxLayout *>(
ui_->horizontalLayout_imageViews->layout())->setDirection(QBoxLayout::LeftToRight);
493 ui_->buttonBox->setVisible(visible);
498 this->setWindowModified(
true);
507 QString privatePath = QDir::homePath() +
"/.rtabmap";
508 if(!QDir(privatePath).exists())
510 QDir::home().mkdir(
".rtabmap");
512 return privatePath +
"/rtabmap.ini";
518 QSettings settings(path, QSettings::IniFormat);
519 settings.beginGroup(
"DatabaseViewer");
523 bytes = settings.value(
"geometry", QByteArray()).toByteArray();
526 this->restoreGeometry(bytes);
528 bytes = settings.value(
"state", QByteArray()).toByteArray();
531 this->restoreState(bytes);
535 ui_->comboBox_logger_level->setCurrentIndex(settings.value(
"loggerLevel",
ui_->comboBox_logger_level->currentIndex()).toInt());
536 ui_->actionVertical_Layout->setChecked(settings.value(
"verticalLayout",
ui_->actionVertical_Layout->isChecked()).toBool());
537 ui_->checkBox_ignoreIntermediateNodes->setChecked(settings.value(
"ignoreIntermediateNodes",
ui_->checkBox_ignoreIntermediateNodes->isChecked()).toBool());
538 ui_->checkBox_timeStats->setChecked(settings.value(
"timeStats",
ui_->checkBox_timeStats->isChecked()).toBool());
541 ui_->graphViewer->loadSettings(settings,
"GraphView");
543 settings.beginGroup(
"optimization");
544 ui_->doubleSpinBox_gainCompensationRadius->setValue(settings.value(
"gainCompensationRadius",
ui_->doubleSpinBox_gainCompensationRadius->value()).toDouble());
545 ui_->doubleSpinBox_voxelSize->setValue(settings.value(
"voxelSize",
ui_->doubleSpinBox_voxelSize->value()).toDouble());
546 ui_->spinBox_decimation->setValue(settings.value(
"decimation",
ui_->spinBox_decimation->value()).toInt());
549 settings.beginGroup(
"grid");
550 ui_->groupBox_posefiltering->setChecked(settings.value(
"poseFiltering",
ui_->groupBox_posefiltering->isChecked()).toBool());
551 ui_->doubleSpinBox_posefilteringRadius->setValue(settings.value(
"poseFilteringRadius",
ui_->doubleSpinBox_posefilteringRadius->value()).toDouble());
552 ui_->doubleSpinBox_posefilteringAngle->setValue(settings.value(
"poseFilteringAngle",
ui_->doubleSpinBox_posefilteringAngle->value()).toDouble());
553 ui_->lineEdit_obstacleColor->setText(settings.value(
"colorObstacle",
ui_->lineEdit_obstacleColor->text()).toString());
554 ui_->lineEdit_groundColor->setText(settings.value(
"colorGround",
ui_->lineEdit_groundColor->text()).toString());
555 ui_->lineEdit_emptyColor->setText(settings.value(
"colorEmpty",
ui_->lineEdit_emptyColor->text()).toString());
556 ui_->spinBox_cropRadius->setValue(settings.value(
"cropRadius",
ui_->spinBox_cropRadius->value()).toInt());
559 settings.beginGroup(
"mesh");
560 ui_->checkBox_mesh_quad->setChecked(settings.value(
"quad",
ui_->checkBox_mesh_quad->isChecked()).toBool());
561 ui_->spinBox_mesh_angleTolerance->setValue(settings.value(
"angleTolerance",
ui_->spinBox_mesh_angleTolerance->value()).toInt());
562 ui_->spinBox_mesh_minClusterSize->setValue(settings.value(
"minClusterSize",
ui_->spinBox_mesh_minClusterSize->value()).toInt());
563 ui_->spinBox_mesh_fillDepthHoles->setValue(settings.value(
"fillDepthHolesSize",
ui_->spinBox_mesh_fillDepthHoles->value()).toInt());
564 ui_->spinBox_mesh_depthError->setValue(settings.value(
"fillDepthHolesError",
ui_->spinBox_mesh_depthError->value()).toInt());
565 ui_->spinBox_mesh_triangleSize->setValue(settings.value(
"triangleSize",
ui_->spinBox_mesh_triangleSize->value()).toInt());
569 ui_->graphicsView_A->loadSettings(settings,
"ImageViewA");
570 ui_->graphicsView_B->loadSettings(settings,
"ImageViewB");
573 settings.beginGroup(
"icp");
574 ui_->spinBox_icp_decimation->setValue(settings.value(
"decimation",
ui_->spinBox_icp_decimation->value()).toInt());
575 ui_->doubleSpinBox_icp_maxDepth->setValue(settings.value(
"maxDepth",
ui_->doubleSpinBox_icp_maxDepth->value()).toDouble());
576 ui_->doubleSpinBox_icp_minDepth->setValue(settings.value(
"minDepth",
ui_->doubleSpinBox_icp_minDepth->value()).toDouble());
577 ui_->checkBox_icp_from_depth->setChecked(settings.value(
"icpFromDepth",
ui_->checkBox_icp_from_depth->isChecked()).toBool());
583 settings.beginGroup(
"Gui");
585 settings.beginGroup(
"PostProcessingDialog");
586 ui_->doubleSpinBox_detectMore_radius->setValue(settings.value(
"cluster_radius",
ui_->doubleSpinBox_detectMore_radius->value()).toDouble());
587 ui_->doubleSpinBox_detectMore_angle->setValue(settings.value(
"cluster_angle",
ui_->doubleSpinBox_detectMore_angle->value()).toDouble());
588 ui_->spinBox_detectMore_iterations->setValue(settings.value(
"iterations",
ui_->spinBox_detectMore_iterations->value()).toInt());
589 ui_->checkBox_detectMore_intraSession->setChecked(settings.value(
"intra_session",
ui_->checkBox_detectMore_intraSession->isChecked()).toBool());
590 ui_->checkBox_detectMore_interSession->setChecked(settings.value(
"inter_session",
ui_->checkBox_detectMore_interSession->isChecked()).toBool());
597 for(ParametersMap::iterator iter = parameters.begin(); iter!= parameters.end(); ++iter)
599 ui_->parameters_toolbox->updateParameter(iter->first, iter->second);
606 QSettings settings(path, QSettings::IniFormat);
607 settings.beginGroup(
"DatabaseViewer");
610 if(!this->isMaximized())
612 settings.setValue(
"geometry", this->saveGeometry());
614 settings.setValue(
"state", this->saveState());
615 settings.setValue(
"maximized", this->isMaximized());
618 settings.setValue(
"loggerLevel",
ui_->comboBox_logger_level->currentIndex());
619 settings.setValue(
"verticalLayout",
ui_->actionVertical_Layout->isChecked());
620 settings.setValue(
"ignoreIntermediateNodes",
ui_->checkBox_ignoreIntermediateNodes->isChecked());
621 settings.setValue(
"timeStats",
ui_->checkBox_timeStats->isChecked());
624 ui_->graphViewer->saveSettings(settings,
"GraphView");
627 settings.beginGroup(
"optimization");
628 settings.setValue(
"gainCompensationRadius",
ui_->doubleSpinBox_gainCompensationRadius->value());
629 settings.setValue(
"voxelSize",
ui_->doubleSpinBox_voxelSize->value());
630 settings.setValue(
"decimation",
ui_->spinBox_decimation->value());
634 settings.beginGroup(
"grid");
635 settings.setValue(
"poseFiltering",
ui_->groupBox_posefiltering->isChecked());
636 settings.setValue(
"poseFilteringRadius",
ui_->doubleSpinBox_posefilteringRadius->value());
637 settings.setValue(
"poseFilteringAngle",
ui_->doubleSpinBox_posefilteringAngle->value());
638 settings.setValue(
"colorObstacle",
ui_->lineEdit_obstacleColor->text());
639 settings.setValue(
"colorGround",
ui_->lineEdit_groundColor->text());
640 settings.setValue(
"colorEmpty",
ui_->lineEdit_emptyColor->text());
641 settings.setValue(
"cropRadius",
ui_->spinBox_cropRadius->value());
644 settings.beginGroup(
"mesh");
645 settings.setValue(
"quad",
ui_->checkBox_mesh_quad->isChecked());
646 settings.setValue(
"angleTolerance",
ui_->spinBox_mesh_angleTolerance->value());
647 settings.setValue(
"minClusterSize",
ui_->spinBox_mesh_minClusterSize->value());
648 settings.setValue(
"fillDepthHolesSize",
ui_->spinBox_mesh_fillDepthHoles->value());
649 settings.setValue(
"fillDepthHolesError",
ui_->spinBox_mesh_depthError->value());
650 settings.setValue(
"triangleSize",
ui_->spinBox_mesh_triangleSize->value());
654 ui_->graphicsView_A->saveSettings(settings,
"ImageViewA");
655 ui_->graphicsView_B->saveSettings(settings,
"ImageViewB");
658 settings.beginGroup(
"icp");
659 settings.setValue(
"decimation",
ui_->spinBox_icp_decimation->value());
660 settings.setValue(
"maxDepth",
ui_->doubleSpinBox_icp_maxDepth->value());
661 settings.setValue(
"minDepth",
ui_->doubleSpinBox_icp_minDepth->value());
662 settings.setValue(
"icpFromDepth",
ui_->checkBox_icp_from_depth->isChecked());
668 settings.beginGroup(
"Gui");
670 settings.beginGroup(
"PostProcessingDialog");
671 settings.setValue(
"cluster_radius",
ui_->doubleSpinBox_detectMore_radius->value());
672 settings.setValue(
"cluster_angle",
ui_->doubleSpinBox_detectMore_angle->value());
673 settings.setValue(
"iterations",
ui_->spinBox_detectMore_iterations->value());
674 settings.setValue(
"intra_session",
ui_->checkBox_detectMore_intraSession->isChecked());
675 settings.setValue(
"inter_session",
ui_->checkBox_detectMore_interSession->isChecked());
680 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end();)
682 if(!
ui_->parameters_toolbox->getParameterWidget(iter->first.c_str()))
684 parameters.erase(iter++);
693 this->setWindowModified(
false);
699 ui_->comboBox_logger_level->setCurrentIndex(1);
700 ui_->checkBox_alignPosesWithGroundTruth->setChecked(
true);
701 ui_->checkBox_alignScansCloudsWithGroundTruth->setChecked(
false);
702 ui_->checkBox_ignoreIntermediateNodes->setChecked(
false);
703 ui_->checkBox_timeStats->setChecked(
true);
705 ui_->checkBox_iterativeOptimization->setChecked(
true);
706 ui_->checkBox_spanAllMaps->setChecked(
true);
707 ui_->checkBox_wmState->setChecked(
false);
708 ui_->checkBox_ignorePoseCorrection->setChecked(
false);
709 ui_->checkBox_ignoreGlobalLoop->setChecked(
false);
710 ui_->checkBox_ignoreLocalLoopSpace->setChecked(
false);
711 ui_->checkBox_ignoreLocalLoopTime->setChecked(
false);
712 ui_->checkBox_ignoreUserLoop->setChecked(
false);
713 ui_->checkBox_ignoreLandmarks->setChecked(
false);
714 ui_->doubleSpinBox_optimizationScale->setValue(1.0);
715 ui_->doubleSpinBox_gainCompensationRadius->setValue(0.0);
716 ui_->doubleSpinBox_voxelSize->setValue(0.0);
717 ui_->spinBox_decimation->setValue(1);
719 ui_->groupBox_posefiltering->setChecked(
false);
720 ui_->doubleSpinBox_posefilteringRadius->setValue(0.1);
721 ui_->doubleSpinBox_posefilteringAngle->setValue(30);
722 ui_->checkBox_grid_empty->setChecked(
true);
723 ui_->checkBox_octomap->setChecked(
false);
724 ui_->lineEdit_obstacleColor->setText(QColor(Qt::red).name());
725 ui_->lineEdit_groundColor->setText(QColor(Qt::green).name());
726 ui_->lineEdit_emptyColor->setText(QColor(Qt::yellow).name());
727 ui_->spinBox_cropRadius->setValue(1);
729 ui_->checkBox_mesh_quad->setChecked(
true);
730 ui_->spinBox_mesh_angleTolerance->setValue(15);
731 ui_->spinBox_mesh_minClusterSize->setValue(0);
732 ui_->spinBox_mesh_fillDepthHoles->setValue(
false);
733 ui_->spinBox_mesh_depthError->setValue(10);
734 ui_->spinBox_mesh_triangleSize->setValue(2);
736 ui_->spinBox_icp_decimation->setValue(1);
737 ui_->doubleSpinBox_icp_maxDepth->setValue(0.0);
738 ui_->doubleSpinBox_icp_minDepth->setValue(0.0);
739 ui_->checkBox_icp_from_depth->setChecked(
false);
741 ui_->doubleSpinBox_detectMore_radius->setValue(1.0);
742 ui_->doubleSpinBox_detectMore_angle->setValue(30.0);
743 ui_->spinBox_detectMore_iterations->setValue(5);
744 ui_->checkBox_detectMore_intraSession->setChecked(
true);
745 ui_->checkBox_detectMore_interSession->setChecked(
true);
750 QString path = QFileDialog::getOpenFileName(
this, tr(
"Select file"),
pathDatabase_, tr(
"Databases (*.db)"));
759 UDEBUG(
"Open database \"%s\"", path.toStdString().c_str());
760 if(QFile::exists(path))
762 if(QFileInfo(path).isFile())
764 std::string driverType =
"sqlite3";
770 ui_->actionClose_database->setEnabled(
false);
771 ui_->actionOpen_database->setEnabled(
true);
774 QMessageBox::warning(
this,
"Database error", tr(
"Can't open database \"%1\"").arg(path));
778 ui_->actionClose_database->setEnabled(
true);
779 ui_->actionOpen_database->setEnabled(
false);
792 if(parameters.size())
794 const ParametersMap & currentParameters =
ui_->parameters_toolbox->getParameters();
796 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
798 ParametersMap::const_iterator jter = currentParameters.find(iter->first);
799 if(jter!=currentParameters.end() &&
800 ui_->parameters_toolbox->getParameterWidget(QString(iter->first.c_str())) != 0 &&
801 iter->second.compare(jter->second) != 0 &&
802 iter->first.compare(Parameters::kRtabmapWorkingDirectory()) != 0)
804 bool different =
true;
815 differentParameters.insert(*iter);
816 QString msg = tr(
"Parameter \"%1\": database=\"%2\" Preferences=\"%3\"")
817 .arg(iter->first.c_str())
818 .arg(iter->second.c_str())
819 .arg(jter->second.c_str());
820 UWARN(msg.toStdString().c_str());
825 if(differentParameters.size())
827 int r = QMessageBox::question(
this,
828 tr(
"Update parameters..."),
829 tr(
"The database is using %1 different parameter(s) than " 830 "those currently set in Core parameters panel. Do you want " 831 "to use database's parameters?").arg(differentParameters.size()),
832 QMessageBox::Yes | QMessageBox::No,
834 if(r == QMessageBox::Yes)
837 for(rtabmap::ParametersMap::const_iterator iter = differentParameters.begin(); iter!=differentParameters.end(); ++iter)
839 ui_->parameters_toolbox->updateParameter(iter->first, iter->second);
840 str.push_back(iter->first.c_str());
848 this->setWindowTitle(
"RTAB-Map Database Viewer - " + path +
"[*]");
864 QMessageBox::warning(
this,
"Database error", tr(
"Database \"%1\" does not exist.").arg(path));
871 this->setWindowTitle(
"RTAB-Map Database Viewer[*]");
876 QMessageBox::StandardButton button = QMessageBox::question(
this,
877 tr(
"Links modified"),
878 tr(
"Some links are modified (%1 added, %2 refined, %3 removed), do you want to save them?")
880 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
881 QMessageBox::Cancel);
883 if(button == QMessageBox::Yes)
886 for(std::multimap<int, rtabmap::Link>::iterator iter=
linksAdded_.begin(); iter!=
linksAdded_.end(); ++iter)
932 if(button != QMessageBox::Yes && button != QMessageBox::No)
941 QMessageBox::StandardButton button = QMessageBox::question(
this,
942 tr(
"Local occupancy grid maps modified"),
943 tr(
"%1 occupancy grid maps are modified, do you want to " 944 "save them? This will overwrite occupancy grids saved in the database.")
946 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
947 QMessageBox::Cancel);
949 if(button == QMessageBox::Yes)
952 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat > >::iterator mapIter =
generatedLocalMaps_.begin();
956 UASSERT(mapIter->first == infoIter->first);
959 mapIter->second.first.first,
960 mapIter->second.first.second,
961 mapIter->second.second,
962 infoIter->second.first,
963 infoIter->second.second);
974 if(button != QMessageBox::Yes && button != QMessageBox::No)
982 QMessageBox::StandardButton button = QMessageBox::question(
this,
983 tr(
"Laser scans modified"),
984 tr(
"%1 laser scans are modified, do you want to " 985 "save them? This will overwrite laser scans saved in the database.")
987 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
988 QMessageBox::Cancel);
990 if(button == QMessageBox::Yes)
999 if(button != QMessageBox::Yes && button != QMessageBox::No)
1030 ui_->graphViewer->clearAll();
1032 ui_->menuEdit->setEnabled(
false);
1033 ui_->actionGenerate_3D_map_pcd->setEnabled(
false);
1034 ui_->actionExport->setEnabled(
false);
1035 ui_->actionExtract_images->setEnabled(
false);
1036 ui_->menuExport_poses->setEnabled(
false);
1037 ui_->menuExport_GPS->setEnabled(
false);
1038 ui_->actionPoses_KML->setEnabled(
false);
1039 ui_->actionEdit_optimized_2D_map->setEnabled(
false);
1040 ui_->actionExport_saved_2D_map->setEnabled(
false);
1041 ui_->actionImport_2D_map->setEnabled(
false);
1042 ui_->actionRegenerate_optimized_2D_map->setEnabled(
false);
1043 ui_->actionView_optimized_mesh->setEnabled(
false);
1044 ui_->actionExport_optimized_mesh->setEnabled(
false);
1045 ui_->actionUpdate_optimized_mesh->setEnabled(
false);
1046 ui_->checkBox_showOptimized->setEnabled(
false);
1047 ui_->toolBox_statistics->clear();
1049 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
false);
1050 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
false);
1051 ui_->doubleSpinBox_optimizationScale->setVisible(
false);
1052 ui_->label_scale_title->setVisible(
false);
1053 ui_->label_rmse->setVisible(
false);
1054 ui_->label_rmse_title->setVisible(
false);
1055 ui_->checkBox_ignoreIntermediateNodes->setVisible(
false);
1056 ui_->label_ignoreINtermediateNdoes->setVisible(
false);
1057 ui_->label_alignPosesWithGroundTruth->setVisible(
false);
1058 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
false);
1059 ui_->label_optimizeFrom->setText(tr(
"Root"));
1060 ui_->textEdit_info->clear();
1062 ui_->pushButton_refine->setEnabled(
false);
1063 ui_->pushButton_add->setEnabled(
false);
1064 ui_->pushButton_reset->setEnabled(
false);
1065 ui_->pushButton_reject->setEnabled(
false);
1067 ui_->horizontalSlider_loops->setEnabled(
false);
1068 ui_->horizontalSlider_loops->setMaximum(0);
1069 ui_->horizontalSlider_iterations->setEnabled(
false);
1070 ui_->horizontalSlider_iterations->setMaximum(0);
1071 ui_->horizontalSlider_neighbors->setEnabled(
false);
1072 ui_->horizontalSlider_neighbors->setMaximum(0);
1073 ui_->label_constraint->clear();
1074 ui_->label_constraint_opt->clear();
1075 ui_->label_variance->clear();
1076 ui_->lineEdit_covariance->clear();
1077 ui_->label_type->clear();
1078 ui_->label_type_name->clear();
1079 ui_->checkBox_showOptimized->setEnabled(
false);
1081 ui_->horizontalSlider_A->setEnabled(
false);
1082 ui_->horizontalSlider_A->setMaximum(0);
1083 ui_->horizontalSlider_B->setEnabled(
false);
1084 ui_->horizontalSlider_B->setMaximum(0);
1085 ui_->label_idA->setText(
"NaN");
1086 ui_->label_idB->setText(
"NaN");
1099 ui_->graphViewer->clearAll();
1100 ui_->label_loopClosures->clear();
1101 ui_->label_timeOptimization->clear();
1102 ui_->label_pathLength->clear();
1103 ui_->label_poses->clear();
1104 ui_->label_rmse->clear();
1105 ui_->spinBox_optimizationsFrom->setEnabled(
false);
1107 ui_->graphicsView_A->clear();
1108 ui_->graphicsView_B->clear();
1110 ui_->graphicsView_stereo->clear();
1114 ui_->toolBox_statistics->clear();
1126 QString path = QFileDialog::getOpenFileName(
this, tr(
"Select file"),
pathDatabase_, tr(
"Databases (*.db)"));
1131 QMessageBox::information(
this,
"Database recovery", tr(
"The selected database is already opened, close it first."));
1134 std::string errorMsg;
1136 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1138 progressDialog->show();
1143 QMessageBox::information(
this,
"Database recovery", tr(
"Database \"%1\" recovered! Try opening it again.").arg(path));
1147 QMessageBox::warning(
this,
"Database recovery", tr(
"Database recovery failed: \"%1\".").arg(errorMsg.c_str()));
1157 if(this->isWindowModified())
1159 QMessageBox::Button b=QMessageBox::question(
this,
1160 tr(
"Database Viewer"),
1161 tr(
"There are unsaved changed settings. Save them?"),
1162 QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard);
1163 if(b == QMessageBox::Save)
1167 else if(b != QMessageBox::Discard)
1186 if(event->isAccepted())
1188 ui_->toolBox_statistics->closeFigures();
1199 this->setWindowModified(
false);
1201 if((
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible()) &&
graphes_.size() &&
localMaps_.size()==0)
1209 if(this->isVisible())
1222 if(this->isVisible())
1231 if((event->modifiers() & Qt::ControlModifier) && event->key() == Qt::Key_S)
1239 if (event->type() == QEvent::Resize && qobject_cast<QDockWidget*>(obj))
1241 this->setWindowModified(
true);
1243 return QWidget::eventFilter(obj, event);
1267 double previousStamp = 0;
1268 std::vector<double> delays(
ids_.size());
1270 std::map<int, Transform> poses;
1271 std::map<int, double> stamps;
1272 std::map<int, Transform> groundTruths;
1273 std::map<int, GPS> gpsValues;
1274 std::map<int, EnvSensors> sensorsValues;
1275 for(
int i=0; i<
ids_.size(); i+=1+framesIgnored)
1282 std::vector<float> velocity;
1287 if(frameRate == 0 ||
1288 previousStamp == 0 ||
1290 stamp - previousStamp >= 1.0/frameRate)
1292 if(sessionExported < 0 || sessionExported == mapId)
1294 ids.push_back(
ids_[i]);
1296 if(previousStamp && stamp)
1298 delays[oi++] = stamp - previousStamp;
1300 previousStamp = stamp;
1302 poses.insert(std::make_pair(
ids_[i], odomPose));
1303 stamps.insert(std::make_pair(
ids_[i], stamp));
1304 groundTruths.insert(std::make_pair(
ids_[i], groundTruth));
1305 if(gps.
stamp() > 0.0)
1307 gpsValues.insert(std::make_pair(
ids_[i], gps));
1311 sensorsValues.insert(std::make_pair(
ids_[i], sensors));
1315 if(sessionExported >= 0 && mapId > sessionExported)
1323 if(recorder.
init(path,
false))
1326 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1328 progressDialog->show();
1330 UINFO(
"Decompress: rgb=%d depth=%d scan=%d userData=%d",
1336 for(
int i=0; i<ids.size() && !progressDialog->
isCanceled(); ++i)
1342 cv::Mat depth, rgb, userData;
1349 cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
1352 std::multimap<int, Link> links;
1354 if(links.size() && links.begin()->first < id)
1356 covariance = links.begin()->second.infMatrix().inv();
1383 if(groundTruths.find(
id)!=groundTruths.end())
1387 if(gpsValues.find(
id)!=gpsValues.end())
1389 sensorData.
setGPS(gpsValues.at(
id));
1391 if(sensorsValues.find(
id)!=sensorsValues.end())
1398 progressDialog->
appendText(tr(
"Exported node %1").arg(
id));
1400 QApplication::processEvents();
1405 progressDialog->
appendText(tr(
"Average frame rate=%1 Hz (Min=%2, Max=%3)")
1406 .arg(1.0/
uMean(delays)).arg(1.0/
uMax(delays)).arg(1.0/
uMin(delays)));
1408 progressDialog->
appendText(tr(
"Export finished to \"%1\"!").arg(path));
1412 UERROR(
"DataRecorder init failed?!");
1417 QMessageBox::warning(
this, tr(
"Cannot export database"), tr(
"An output path must be set!"));
1429 QStringList formats;
1430 formats.push_back(
"jpg");
1431 formats.push_back(
"png");
1433 QString ext = QInputDialog::getItem(
this, tr(
"Which RGB format?"), tr(
"Format:"), formats, 0,
false, &ok);
1439 QString path = QFileDialog::getExistingDirectory(
this, tr(
"Select directory where to save images..."), QDir::homePath());
1444 int id =
ids_.at(0);
1451 dir.mkdir(QString(
"%1/left").arg(path));
1452 dir.mkdir(QString(
"%1/right").arg(path));
1455 UERROR(
"Cannot save calibration file, database name is empty!");
1477 if(model.save(path.toStdString()))
1479 UINFO(
"Saved stereo calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1483 UERROR(
"Failed saving calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1492 dir.mkdir(QString(
"%1/rgb").arg(path));
1493 dir.mkdir(QString(
"%1/depth").arg(path));
1498 UERROR(
"Cannot save calibration file, database name is empty!");
1502 UERROR(
"Only one camera calibration can be saved at this time (%d detected)", (
int)data.
cameraModels().size());
1514 if(model.save(path.toStdString()))
1516 UINFO(
"Saved calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1520 UERROR(
"Failed saving calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1526 int imagesExported = 0;
1527 for(
int i=0; i<
ids_.size(); ++i)
1529 int id =
ids_.at(i);
1535 cv::imwrite(QString(
"%1/left/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
imageRaw());
1536 cv::imwrite(QString(
"%1/right/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
rightRaw());
1537 UINFO(QString(
"Saved left/%1.%2 and right/%1.%2").arg(
id).arg(ext).toStdString().c_str());
1542 cv::imwrite(QString(
"%1/rgb/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
imageRaw());
1544 UINFO(QString(
"Saved rgb/%1.%2 and depth/%1.png").arg(
id).arg(ext).toStdString().c_str());
1549 cv::imwrite(QString(
"%1/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
imageRaw());
1550 UINFO(QString(
"Saved %1.%2").arg(
id).arg(ext).toStdString().c_str());
1554 QMessageBox::information(
this, tr(
"Exporting"), tr(
"%1 images exported!").arg(imagesExported));
1566 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1567 int progressSteps = 5;
1568 if(
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
1572 if(
ui_->textEdit_info->isVisible())
1576 if(
ui_->toolBox_statistics->isVisible())
1581 progressDialog->show();
1584 progressDialog->
appendText(tr(
"Loading all ids..."));
1585 QApplication::processEvents();
1587 QApplication::processEvents();
1589 UINFO(
"Loading all IDs...");
1592 ids_ = QList<int>::fromStdList(std::list<int>(ids.begin(), ids.end()));
1604 ui_->checkBox_wmState->setVisible(
false);
1605 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
false);
1606 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
false);
1607 ui_->doubleSpinBox_optimizationScale->setVisible(
false);
1608 ui_->label_scale_title->setVisible(
false);
1609 ui_->label_rmse->setVisible(
false);
1610 ui_->label_rmse_title->setVisible(
false);
1611 ui_->checkBox_ignoreIntermediateNodes->setVisible(
false);
1612 ui_->label_ignoreINtermediateNdoes->setVisible(
false);
1613 ui_->label_alignPosesWithGroundTruth->setVisible(
false);
1614 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
false);
1615 ui_->menuEdit->setEnabled(
true);
1616 ui_->actionGenerate_3D_map_pcd->setEnabled(
true);
1617 ui_->actionExport->setEnabled(
true);
1618 ui_->actionExtract_images->setEnabled(
true);
1619 ui_->menuExport_poses->setEnabled(
false);
1620 ui_->menuExport_GPS->setEnabled(
false);
1621 ui_->actionPoses_KML->setEnabled(
false);
1622 ui_->actionEdit_optimized_2D_map->setEnabled(
false);
1623 ui_->actionExport_saved_2D_map->setEnabled(
false);
1624 ui_->actionImport_2D_map->setEnabled(
false);
1625 ui_->actionRegenerate_optimized_2D_map->setEnabled(
false);
1626 ui_->actionView_optimized_mesh->setEnabled(
false);
1627 ui_->actionExport_optimized_mesh->setEnabled(
false);
1633 ui_->toolBox_statistics->clear();
1634 ui_->label_optimizeFrom->setText(tr(
"Root"));
1636 progressDialog->
appendText(tr(
"%1 ids loaded!").arg(ids.size()));
1638 progressDialog->
appendText(tr(
"Loading all links..."));
1639 QApplication::processEvents();
1641 QApplication::processEvents();
1643 std::multimap<int, Link> unilinks;
1645 UDEBUG(
"%d total links loaded", (
int)unilinks.size());
1647 std::multimap<int, Link> links;
1648 for(std::multimap<int, Link>::iterator iter=unilinks.begin(); iter!=unilinks.end(); ++iter)
1650 links.insert(*iter);
1651 if(
graph::findLink(unilinks, iter->second.to(), iter->second.from(),
false) == unilinks.end())
1653 links.insert(std::make_pair(iter->second.to(), iter->second.inverse()));
1657 progressDialog->
appendText(tr(
"%1 links loaded!").arg(unilinks.size()));
1659 progressDialog->
appendText(
"Loading Working Memory state...");
1660 QApplication::processEvents();
1662 QApplication::processEvents();
1668 double previousStamp = 0.0;
1672 progressDialog->
appendText(
"Loading Working Memory state... done!");
1674 progressDialog->
appendText(
"Loading info for all nodes...");
1675 QApplication::processEvents();
1677 QApplication::processEvents();
1679 for(
int i=0; i<
ids_.size(); ++i)
1688 std::vector<float> v;
1694 if(wmStates.find(
ids_[i]) != wmStates.end())
1697 ui_->checkBox_wmState->setVisible(
true);
1701 ui_->checkBox_ignoreIntermediateNodes->setVisible(
true);
1702 ui_->label_ignoreINtermediateNdoes->setVisible(
true);
1713 if(previousStamp > 0.0 && s > 0.0)
1727 bool addPose = links.find(
ids_[i]) == links.end();
1728 for(std::multimap<int, Link>::iterator jter=links.find(
ids_[i]); jter!=links.end() && jter->first ==
ids_[i]; ++jter)
1735 std::multimap<int, Link>::iterator invertedLinkIter =
graph::findLink(links, jter->second.to(), jter->second.from(),
false);
1736 if( jter->second.isValid() &&
1737 ids.find(jter->second.from()) != ids.end() &&
1738 (ids.find(jter->second.to()) != ids.end() || jter->second.to()<0) &&
1740 invertedLinkIter != links.end())
1743 if(jter->second.userDataCompressed().cols == 0 &&
1744 invertedLinkIter->second.userDataCompressed().cols != 0)
1746 links_.insert(std::make_pair(invertedLinkIter->second.from(), invertedLinkIter->second));
1750 links_.insert(std::make_pair(
ids_[i], jter->second));
1766 if(gps.
stamp() > 0.0)
1770 cv::Point3f p(0.0
f,0.0
f,0.0
f);
1783 progressDialog->
appendText(
"Loading info for all nodes... done!");
1785 progressDialog->
appendText(
"Loading optimized poses and maps...");
1786 QApplication::processEvents();
1788 QApplication::processEvents();
1792 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
true);
1793 ui_->doubleSpinBox_optimizationScale->setVisible(
true);
1794 ui_->label_scale_title->setVisible(
true);
1795 ui_->label_rmse->setVisible(
true);
1796 ui_->label_rmse_title->setVisible(
true);
1797 ui_->label_alignPosesWithGroundTruth->setVisible(
true);
1801 ui_->label_alignPosesWithGroundTruth->setText(tr(
"Align poses with ground truth"));
1802 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
true);
1803 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
true);
1807 ui_->label_alignPosesWithGroundTruth->setText(tr(
"Align poses with GPS"));
1812 ui_->menuExport_GPS->setEnabled(
true);
1816 float xMin, yMin, cellSize;
1818 ui_->actionEdit_optimized_2D_map->setEnabled(hasMap);
1819 ui_->actionExport_saved_2D_map->setEnabled(hasMap);
1820 ui_->actionImport_2D_map->setEnabled(hasMap);
1825 ui_->actionView_optimized_mesh->setEnabled(
true);
1826 ui_->actionExport_optimized_mesh->setEnabled(
true);
1831 progressDialog->
appendText(
"Loading optimized poses and maps... done!");
1833 QApplication::processEvents();
1835 QApplication::processEvents();
1837 if(
ids_.size() &&
ui_->toolBox_statistics->isVisible())
1839 progressDialog->
appendText(
"Loading statistics...");
1840 QApplication::processEvents();
1842 QApplication::processEvents();
1844 UINFO(
"Update statistics...");
1847 progressDialog->
appendText(
"Loading statistics... done!");
1849 QApplication::processEvents();
1851 QApplication::processEvents();
1855 ui_->textEdit_info->clear();
1856 if(
ui_->textEdit_info->isVisible())
1858 progressDialog->
appendText(
"Update database info...");
1859 QApplication::processEvents();
1861 QApplication::processEvents();
1865 progressDialog->
appendText(
"Update database info... done!");
1867 QApplication::processEvents();
1869 QApplication::processEvents();
1876 bool nullPoses =
odomPoses_.begin()->second.isNull();
1879 if((!iter->second.isNull() && nullPoses) ||
1880 (iter->second.isNull() && !nullPoses))
1882 if(iter->second.isNull())
1884 UWARN(
"Pose %d is null!", iter->first);
1886 UWARN(
"Mixed valid and null poses! Ignoring graph...");
1901 ui_->spinBox_optimizationsFrom->setValue(
odomPoses_.begin()->first);
1902 ui_->label_optimizeFrom->setText(tr(
"Root [%1, %2]").arg(
odomPoses_.begin()->first).arg(
odomPoses_.rbegin()->first));
1907 ui_->menuExport_poses->setEnabled(
false);
1912 for(std::multimap<int, rtabmap::Link>::iterator iter =
links_.begin(); iter!=
links_.end(); ++iter)
1914 if(!iter->second.transform().isNull())
1921 else if(iter->second.from()!=iter->second.to())
1928 UERROR(
"Transform null for link from %d to %d", iter->first, iter->second.to());
1934 ui_->horizontalSlider_A->setMinimum(0);
1935 ui_->horizontalSlider_B->setMinimum(0);
1936 ui_->horizontalSlider_A->setMaximum(
ids_.size()-1);
1937 ui_->horizontalSlider_B->setMaximum(
ids_.size()-1);
1938 ui_->horizontalSlider_A->setEnabled(
true);
1939 ui_->horizontalSlider_B->setEnabled(
true);
1940 ui_->horizontalSlider_A->setSliderPosition(0);
1941 ui_->horizontalSlider_B->setSliderPosition(0);
1947 ui_->horizontalSlider_A->setEnabled(
false);
1948 ui_->horizontalSlider_B->setEnabled(
false);
1949 ui_->label_idA->setText(
"NaN");
1950 ui_->label_idB->setText(
"NaN");
1955 ui_->horizontalSlider_neighbors->setMinimum(0);
1957 ui_->horizontalSlider_neighbors->setEnabled(
true);
1958 ui_->horizontalSlider_neighbors->setSliderPosition(0);
1962 ui_->horizontalSlider_neighbors->setEnabled(
false);
1968 if(
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
1970 progressDialog->
appendText(
"Updating Graph View...");
1971 QApplication::processEvents();
1973 QApplication::processEvents();
1977 progressDialog->
appendText(
"Updating Graph View... done!");
1979 QApplication::processEvents();
1981 QApplication::processEvents();
1989 UINFO(
"Update database info...");
1992 if(
ui_->textEdit_info->toPlainText().isEmpty())
1999 ui_->textEdit_info->append(tr(
"Total odometry length:\t%1 m (approx. as graph has been reduced)").arg(
infoTotalOdom_));
2003 ui_->textEdit_info->append(tr(
"Total odometry length:\t%1 m").arg(
infoTotalOdom_));
2006 int lastWordIdId = 0;
2013 ids.insert(lastWordIdId);
2014 std::list<VisualWord *> vws;
2018 wordsDim = vws.front()->getDescriptor().cols;
2019 wordsType = vws.front()->getDescriptor().type();
2025 ui_->textEdit_info->append(tr(
"Total time:\t\t%1").arg(QDateTime::fromMSecsSinceEpoch(
infoTotalTime_*1000).toUTC().toString(
"hh:mm:ss.zzz")));
2028 ui_->textEdit_info->append(tr(
"Global graph:\t%1 poses and %2 links").arg(
odomPoses_.size()).arg(
links_.size()));
2030 ui_->textEdit_info->append(tr(
"GPS:\t%1 poses").arg(
gpsValues_.size()));
2031 ui_->textEdit_info->append(
"");
2035 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"));
2038 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"));
2041 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"));
2044 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"));
2047 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"));
2050 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"));
2053 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"));
2056 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"));
2059 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"));
2062 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"));
2065 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"));
2068 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"));
2069 mem = dbSize - total;
2070 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"));
2071 ui_->textEdit_info->append(
"");
2072 std::set<int> idsWithoutBad;
2074 int infoBadcountInLTM = 0;
2075 int infoBadCountInGraph = 0;
2076 for(
int i=0; i<
ids_.size(); ++i)
2078 if(idsWithoutBad.find(
ids_[i]) == idsWithoutBad.end())
2080 ++infoBadcountInLTM;
2083 ++infoBadCountInGraph;
2087 ui_->textEdit_info->append(tr(
"%1 bad signatures in LTM").arg(infoBadcountInLTM));
2088 ui_->textEdit_info->append(tr(
"%1 bad signatures in the global graph").arg(infoBadCountInGraph));
2089 ui_->textEdit_info->append(
"");
2091 QFontMetrics metrics(
ui_->textEdit_info->font());
2092 int tabW =
ui_->textEdit_info->tabStopWidth();
2093 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
2095 int strW = metrics.width(QString(iter->first.c_str()) +
"=");
2096 ui_->textEdit_info->append(tr(
"%1=%2%3")
2097 .arg(iter->first.c_str())
2098 .arg(strW < tabW?
"\t\t\t\t":strW < tabW*2?
"\t\t\t":strW < tabW*3?
"\t\t":
"\t")
2099 .arg(iter->second.c_str()));
2103 ui_->textEdit_info->moveCursor(QTextCursor::Start) ;
2104 ui_->textEdit_info->ensureCursorVisible() ;
2109 ui_->textEdit_info->clear();
2118 ui_->toolBox_statistics->clear();
2119 double firstStamp = 0.0;
2122 std::map<std::string, std::pair<std::vector<qreal>, std::vector<qreal> > > allData;
2123 std::map<std::string, int > allDataOi;
2125 for(
int i=0; i<
ids_.size(); ++i)
2128 std::map<std::string, float> statistics;
2129 if(allStats.find(
ids_[i]) != allStats.end())
2131 statistics = allStats.at(
ids_[i]).first;
2132 stamp = allStats.at(
ids_[i]).second;
2138 for(std::map<std::string, float>::iterator iter=statistics.begin(); iter!=statistics.end(); ++iter)
2140 if(allData.find(iter->first) == allData.end())
2143 allData.insert(std::make_pair(iter->first, std::make_pair(std::vector<qreal>(
ids_.size(), 0.0f), std::vector<qreal>(
ids_.size(), 0.0f) )));
2144 allDataOi.insert(std::make_pair(iter->first, 0));
2147 int & oi = allDataOi.at(iter->first);
2148 allData.at(iter->first).first[oi] =
ui_->checkBox_timeStats->isChecked()?qreal(stamp-firstStamp):
ids_[i];
2149 allData.at(iter->first).second[oi] = iter->second;
2154 for(std::map<std::string, std::pair<std::vector<qreal>, std::vector<qreal> > >::iterator iter=allData.begin(); iter!=allData.end(); ++iter)
2156 int oi = allDataOi.at(iter->first);
2157 iter->second.first.resize(oi);
2158 iter->second.second.resize(oi);
2159 ui_->toolBox_statistics->updateStat(iter->first.c_str(), iter->second.first, iter->second.second,
true);
2167 QColor c = QColorDialog::getColor(
ui_->lineEdit_obstacleColor->text(),
this);
2170 ui_->lineEdit_obstacleColor->setText(c.name());
2175 QColor c = QColorDialog::getColor(
ui_->lineEdit_groundColor->text(),
this);
2178 ui_->lineEdit_groundColor->setText(c.name());
2183 QColor c = QColorDialog::getColor(
ui_->lineEdit_emptyColor->text(),
this);
2186 ui_->lineEdit_emptyColor->setText(c.name());
2252 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
2254 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No graph in database?!"));
2263 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No GPS in database?!"));
2267 std::map<int, rtabmap::Transform> graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
2270 pcl::PointCloud<pcl::PointXYZ> cloud1, cloud2;
2271 cloud1.resize(graph.size());
2272 cloud2.resize(graph.size());
2275 for(std::map<int, Transform>::const_iterator iter=
gpsPoses_.begin(); iter!=
gpsPoses_.end(); ++iter)
2277 std::map<int, Transform>::iterator iter2 = graph.find(iter->first);
2278 if(iter2!=graph.end())
2282 idFirst = iter->first;
2284 cloud1[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
2285 cloud2[oi++] = pcl::PointXYZ(iter2->second.x(), iter2->second.y(), iter2->second.z());
2299 t =
gpsPoses_.at(idFirst) * graph.at(idFirst).inverse();
2302 std::map<int, GPS> values;
2304 for(std::map<int, Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
2306 iter->second = t * iter->second;
2309 coord.
fromENU_WGS84(cv::Point3d(iter->second.x(), iter->second.y(), iter->second.z()), origin);
2310 double bearing = -(iter->second.theta()*180.0/
M_PI-90.0);
2321 std::vector<float> v;
2328 QString output =
pathDatabase_ + QDir::separator() +
"poses.kml";
2329 QString path = QFileDialog::getSaveFileName(
2333 tr(
"Google Earth file (*.kml)"));
2337 bool saved =
graph::exportGPS(path.toStdString(), values,
ui_->graphViewer->getNodeColor().rgba());
2341 QMessageBox::information(
this,
2342 tr(
"Export poses..."),
2343 tr(
"GPS coordinates saved to \"%1\".")
2348 QMessageBox::information(
this,
2349 tr(
"Export poses..."),
2350 tr(
"Failed to save GPS coordinates to \"%1\"!")
2358 std::map<int, Transform> optimizedPoses;
2367 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked())
2370 if(refPoses.empty())
2378 float translational_rmse = 0.0f;
2379 float translational_mean = 0.0f;
2380 float translational_median = 0.0f;
2381 float translational_std = 0.0f;
2382 float translational_min = 0.0f;
2383 float translational_max = 0.0f;
2384 float rotational_rmse = 0.0f;
2385 float rotational_mean = 0.0f;
2386 float rotational_median = 0.0f;
2387 float rotational_std = 0.0f;
2388 float rotational_min = 0.0f;
2389 float rotational_max = 0.0f;
2396 translational_median,
2407 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked() && !gtToMap.
isIdentity())
2409 for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
2411 iter->second = gtToMap * iter->second;
2418 if(optimizedPoses.size())
2420 std::map<int, Transform> localTransforms;
2422 items.push_back(
"Robot (base frame)");
2423 items.push_back(
"Camera");
2424 items.push_back(
"Scan");
2426 QString item = QInputDialog::getItem(
this, tr(
"Export Poses"), tr(
"Frame: "), items, 0,
false, &ok);
2427 if(!ok || item.isEmpty())
2431 if(item.compare(
"Robot (base frame)") != 0)
2433 bool cameraFrame = item.compare(
"Camera") == 0;
2434 for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
2439 std::vector<CameraModel> models;
2443 if((models.size() == 1 &&
2444 !models.at(0).localTransform().isNull()))
2446 localTransform = models.at(0).localTransform();
2452 else if(models.size()>1)
2454 UWARN(
"Multi-camera is not supported (node %d)", iter->first);
2458 UWARN(
"Calibration not valid for node %d", iter->first);
2463 UWARN(
"Missing calibration for node %d", iter->first);
2475 UWARN(
"Missing scan info for node %d", iter->first);
2479 if(!localTransform.
isNull())
2481 localTransforms.insert(std::make_pair(iter->first, localTransform));
2484 if(localTransforms.empty())
2486 QMessageBox::warning(
this,
2488 tr(
"Could not find any \"%1\" frame, exporting in Robot frame instead.").arg(item));
2492 std::map<int, Transform> poses;
2493 std::multimap<int, Link> links;
2494 if(localTransforms.empty())
2496 poses = optimizedPoses;
2502 for(std::map<int, Transform>::iterator iter=localTransforms.begin(); iter!=localTransforms.end(); ++iter)
2504 poses.insert(std::make_pair(iter->first, optimizedPoses.at(iter->first) * iter->second));
2510 std::multimap<int, Link>::iterator inserted = links.insert(*iter);
2511 int from = iter->second.from();
2512 int to = iter->second.to();
2513 inserted->second.setTransform(localTransforms.at(from).inverse()*iter->second.transform()*localTransforms.at(to));
2518 std::map<int, double> stamps;
2519 if(format == 1 || format == 10)
2521 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
2528 std::vector<float> v;
2533 stamps.insert(std::make_pair(iter->first, stamp));
2536 if(stamps.size()!=poses.size())
2538 QMessageBox::warning(
this, tr(
"Export poses..."), tr(
"Poses (%1) and stamps (%2) have not the same size! Cannot export in RGB-D SLAM format.")
2539 .arg(poses.size()).arg(stamps.size()));
2544 QString output =
pathDatabase_ + QDir::separator() + (format==3?
"toro.graph":format==4?
"poses.g2o":
"poses.txt");
2546 QString path = QFileDialog::getSaveFileName(
2550 format == 3?tr(
"TORO file (*.graph)"):format==4?tr(
"g2o file (*.g2o)"):tr(
"Text file (*.txt)"));
2554 if(QFileInfo(path).suffix() ==
"")
2570 bool saved =
graph::exportPoses(path.toStdString(), format, poses, links, stamps,
ui_->parameters_toolbox->getParameters());
2574 QMessageBox::information(
this,
2575 tr(
"Export poses..."),
2576 tr(
"%1 saved to \"%2\".")
2577 .arg(format == 3?
"TORO graph":format == 4?
"g2o graph":
"Poses")
2582 QMessageBox::information(
this,
2583 tr(
"Export poses..."),
2584 tr(
"Failed to save %1 to \"%2\"!")
2585 .arg(format == 3?
"TORO graph":format == 4?
"g2o graph":
"poses")
2605 QString output =
pathDatabase_ + QDir::separator() + (format==0?
"gps.txt":
"gps.kml");
2606 QString path = QFileDialog::getSaveFileName(
2610 format==0?tr(
"Raw format (*.txt)"):tr(
"Google Earth file (*.kml)"));
2618 QMessageBox::information(
this,
2619 tr(
"Export poses..."),
2620 tr(
"GPS coordinates saved to \"%1\".")
2625 QMessageBox::information(
this,
2626 tr(
"Export poses..."),
2627 tr(
"Failed to save GPS coordinates to \"%1\"!")
2638 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
2644 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
2645 tr(
"The database has too old version (%1) to saved " 2652 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
2653 tr(
"The database has modified links and/or modified local " 2654 "occupancy grids, the 2D optimized map cannot be modified."));
2658 float xMin, yMin, cellSize;
2662 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"The database doesn't contain a saved 2D map."));
2667 cv::Mat map8UFlip, map8URotated;
2668 cv::flip(map8U, map8UFlip, 0);
2669 if(!
ui_->graphViewer->isOrientationENU())
2672 cv::transpose(map8UFlip, map8URotated);
2673 cv::flip(map8URotated, map8URotated, 0);
2677 map8URotated = map8UFlip;
2686 if(!
ui_->graphViewer->isOrientationENU())
2689 cv::transpose(mapModified, map8URotated);
2690 cv::flip(map8URotated, map8URotated, 1);
2694 map8URotated = mapModified;
2696 cv::flip(map8URotated, map8UFlip, 0);
2698 UASSERT(map8UFlip.type() == map8U.type());
2699 UASSERT(map8UFlip.cols == map8U.cols);
2700 UASSERT(map8UFlip.rows == map8U.rows);
2707 QMessageBox::information(
this, tr(
"Edit 2D map"), tr(
"Map updated!"));
2710 int cropRadius =
ui_->spinBox_cropRadius->value();
2711 QMessageBox::StandardButton b = QMessageBox::question(
this,
2712 tr(
"Crop empty space"),
2713 tr(
"Do you want to clear empty space from local occupancy grids and laser scans?\n\n" 2715 " * 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" 2716 " * 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" 2718 " * Cropping the laser scans cannot be reverted after the viewer is closed and changes have been saved.\n\n" 2720 " Crop radius = %1 pixels\n\n" 2721 "Press \"Yes\" to filter only grids.\n" 2722 "Press \"Yes to All\" to filter both grids and laser scans.\n").arg(cropRadius),
2723 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No, QMessageBox::No);
2724 if(b == QMessageBox::Yes || b == QMessageBox::YesToAll)
2732 progressDialog.show();
2734 progressDialog.
appendText(QString(
"Cropping empty space... %1 scans to filter").arg(poses.size()));
2735 progressDialog.setMinimumWidth(800);
2736 QApplication::processEvents();
2738 UINFO(
"Cropping empty space... poses=%d cropRadius=%d", poses.size(), cropRadius);
2740 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end() && !progressDialog.
isCanceled(); ++iter)
2744 cv::Mat gridObstacles;
2751 data.
uncompressData(0,0,&scan,0,&gridGround,&gridObstacles,&gridEmpty);
2757 if(!gridObstacles.empty())
2759 cv::Mat filtered = cv::Mat(1, gridObstacles.cols, gridObstacles.type());
2761 for(
int i=0; i<gridObstacles.cols; ++i)
2763 const float * ptr = gridObstacles.ptr<
float>(0, i);
2764 cv::Point3f pt(ptr[0], ptr[1], gridObstacles.channels()==2?0:ptr[2]);
2767 int x = int((pt.x - xMin) / cellSize + 0.5f);
2768 int y = int((pt.y - yMin) / cellSize + 0.5f);
2770 if(x>=0 && x<map8S.cols &&
2771 y>=0 && y<map8S.rows)
2773 bool obstacleDetected =
false;
2775 for(
int j=-cropRadius; j<=cropRadius && !obstacleDetected; ++j)
2777 for(
int k=-cropRadius; k<=cropRadius && !obstacleDetected; ++k)
2779 if(x+j>=0 && x+j<map8S.cols &&
2780 y+k>=0 && y+k<map8S.rows &&
2781 map8S.at<
unsigned char>(y+k,x+j) == 100)
2783 obstacleDetected =
true;
2788 if(map8S.at<
unsigned char>(y,x) != 0 || obstacleDetected)
2797 if(oi != gridObstacles.cols)
2799 progressDialog.
appendText(QString(
"Grid %1 filtered %2 pts -> %3 pts").arg(iter->first).arg(gridObstacles.cols).arg(oi));
2800 UINFO(
"Grid %d filtered %d -> %d", iter->first, gridObstacles.cols, oi);
2803 std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> value;
2810 value.first.first = gridGround;
2811 value.second = gridEmpty;
2814 value.first.second = cv::Mat(filtered,
cv::Range::all(), cv::Range(0, oi));
2819 if(b == QMessageBox::YesToAll && !scan.
isEmpty())
2823 cv::Mat filtered = cv::Mat(1, scan.
size(), scan.
dataType());
2825 for(
int i=0; i<scan.
size(); ++i)
2827 const float * ptr = scan.
data().ptr<
float>(0, i);
2828 cv::Point3f pt(ptr[0], ptr[1], scan.
is2d()?0:ptr[2]);
2831 int x = int((pt.x - xMin) / cellSize + 0.5f);
2832 int y = int((pt.y - yMin) / cellSize + 0.5f);
2834 if(x>=0 && x<map8S.cols &&
2835 y>=0 && y<map8S.rows)
2837 bool obstacleDetected =
false;
2839 for(
int j=-cropRadius; j<=cropRadius && !obstacleDetected; ++j)
2841 for(
int k=-cropRadius; k<=cropRadius && !obstacleDetected; ++k)
2843 if(x+j>=0 && x+j<map8S.cols &&
2844 y+k>=0 && y+k<map8S.rows &&
2845 map8S.at<
unsigned char>(y+k,x+j) == 100)
2847 obstacleDetected =
true;
2852 if(map8S.at<
unsigned char>(y,x) != 0 || obstacleDetected)
2861 if(oi != scan.
size())
2863 progressDialog.
appendText(QString(
"Scan %1 filtered %2 pts -> %3 pts").arg(iter->first).arg(scan.
size()).arg(oi));
2864 UINFO(
"Scan %d filtered %d -> %d", iter->first, scan.
size(), oi);
2894 QApplication::processEvents();
2914 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
2918 float xMin, yMin, cellSize;
2922 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"The database doesn't contain a saved 2D map."));
2928 QString path = QFileDialog::getSaveFileName(
2936 if(QFileInfo(path).suffix() ==
"")
2940 cv::imwrite(path.toStdString(), map8U);
2941 QMessageBox::information(
this, tr(
"Export 2D map"), tr(
"Exported %1!").arg(path));
2950 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
2956 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
2957 tr(
"The database has too old version (%1) to saved " 2964 QMessageBox::warning(
this, tr(
"Cannot import 2D map"),
2965 tr(
"The database has modified links and/or modified local " 2966 "occupancy grids, the 2D optimized map cannot be modified."));
2970 float xMin, yMin, cellSize;
2974 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"The database doesn't contain a saved 2D map."));
2978 QString path = QFileDialog::getOpenFileName(
2985 cv::Mat map8U = cv::imread(path.toStdString(), cv::IMREAD_UNCHANGED);
2988 if(mapOrg.cols == map.cols && mapOrg.rows == map8U.rows)
2991 QMessageBox::information(
this, tr(
"Import 2D map"), tr(
"Imported %1!").arg(path));
2995 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));
3005 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
3011 QMessageBox::warning(
this, tr(
"Cannot edit 2D map"),
3012 tr(
"The database has too old version (%1) to saved " 3019 QMessageBox::warning(
this, tr(
"Cannot import 2D map"),
3020 tr(
"The database has modified links and/or modified local " 3021 "occupancy grids, the 2D optimized map cannot be modified. Try " 3022 "closing the database and re-open it to save the changes."));
3028 QMessageBox::warning(
this, tr(
"Cannot regenerate 2D map"),
3029 tr(
"Graph is empty, make sure you opened the " 3030 "Graph View and there is a map shown."));
3036 UINFO(
"Update local maps list...");
3038 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=
localMaps_.begin(); iter!=
localMaps_.end(); ++iter)
3040 grid.
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second);
3044 cv::Mat map = grid.getMap(xMin, yMin);
3048 QMessageBox::information(
this, tr(
"Regenerate 2D map"), tr(
"Failed to renegerate the map, resulting map is empty!"));
3058 lastlocalizationPose =
graphes_.back().rbegin()->second;
3063 QMessageBox::information(
this, tr(
"Regenerate 2D map"), tr(
"Map regenerated!"));
3064 ui_->actionEdit_optimized_2D_map->setEnabled(
true);
3065 ui_->actionExport_saved_2D_map->setEnabled(
true);
3066 ui_->actionImport_2D_map->setEnabled(
true);
3074 QMessageBox::warning(
this, tr(
"Cannot view optimized mesh"), tr(
"A database must must loaded first...\nUse File->Open database."));
3078 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3079 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 3080 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3082 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3086 if(cloudMat.empty())
3088 QMessageBox::warning(
this, tr(
"Cannot view optimized mesh"), tr(
"The database doesn't contain a saved optimized mesh."));
3093 viewer->setWindowFlags(Qt::Window);
3094 viewer->setAttribute(Qt::WA_DeleteOnClose);
3096 if(!textures.empty())
3100 viewer->setWindowTitle(
"Optimized Textured Mesh");
3104 else if(polygons.size() == 1)
3107 viewer->setWindowTitle(
"Optimized Mesh");
3115 viewer->setWindowTitle(
"Optimized Point Cloud");
3126 QMessageBox::warning(
this, tr(
"Cannot export optimized mesh"), tr(
"A database must must loaded first...\nUse File->Open database."));
3130 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
3131 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 3132 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
3134 std::vector<std::vector<Eigen::Vector2f> > texCoords;
3138 if(cloudMat.empty())
3140 QMessageBox::warning(
this, tr(
"Cannot export optimized mesh"), tr(
"The database doesn't contain a saved optimized mesh."));
3146 if(!textures.empty())
3149 QString path = QFileDialog::getSaveFileName(
3153 tr(
"Mesh (*.obj)"));
3157 if(QFileInfo(path).suffix() ==
"")
3161 QString baseName = QFileInfo(path).baseName();
3162 if(mesh->tex_materials.size() == 1)
3164 mesh->tex_materials.at(0).tex_file = baseName.toStdString() +
".png";
3165 cv::imwrite((QFileInfo(path).absoluteDir().absolutePath()+QDir::separator()+baseName).toStdString() +
".png", textures);
3169 for(
unsigned int i=0; i<mesh->tex_materials.size(); ++i)
3171 mesh->tex_materials.at(i).tex_file = (baseName+QDir::separator()+QString::number(i)+
".png").toStdString();
3172 UASSERT((i+1)*textures.rows <= (
unsigned int)textures.cols);
3173 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)));
3176 pcl::io::saveOBJFile(path.toStdString(), *mesh);
3178 QMessageBox::information(
this, tr(
"Export Textured Mesh"), tr(
"Exported %1!").arg(path));
3181 else if(polygons.size() == 1)
3184 QString path = QFileDialog::getSaveFileName(
3188 tr(
"Mesh (*.ply)"));
3192 if(QFileInfo(path).suffix() ==
"")
3196 pcl::io::savePLYFileBinary(path.toStdString(), *mesh);
3197 QMessageBox::information(
this, tr(
"Export Mesh"), tr(
"Exported %1!").arg(path));
3202 QString path = QFileDialog::getSaveFileName(
3206 tr(
"Point cloud data (*.ply *.pcd)"));
3210 if(QFileInfo(path).suffix() ==
"")
3214 bool success =
false;
3216 if(QFileInfo(path).suffix() ==
"pcd")
3218 success = pcl::io::savePCDFile(path.toStdString(), *cloud) == 0;
3222 success = pcl::io::savePLYFile(path.toStdString(), *cloud) == 0;
3226 QMessageBox::information(
this, tr(
"Export Point Cloud"), tr(
"Exported %1!").arg(path));
3230 QMessageBox::critical(
this, tr(
"Export Point Cloud"), tr(
"Failed exporting %1!").arg(path));
3241 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
3248 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3250 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3255 std::map<int, Transform> optimizedPoses;
3264 if(
ui_->groupBox_posefiltering->isChecked())
3267 ui_->doubleSpinBox_posefilteringRadius->value(),
3268 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
3274 if(optimizedPoses.size() > 0)
3280 std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr> clouds;
3281 std::map<int, pcl::PolygonMesh::Ptr> meshes;
3282 std::map<int, pcl::TextureMesh::Ptr> textureMeshes;
3283 std::vector<std::map<int, pcl::PointXY> > textureVertexToPixels;
3289 QMap<int, Signature>(),
3290 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
3291 std::map<int, LaserScan>(),
3293 ui_->parameters_toolbox->getParameters(),
3297 textureVertexToPixels))
3299 if(textureMeshes.size())
3303 cv::Mat globalTextures;
3304 pcl::TextureMeshPtr textureMesh = textureMeshes.at(0);
3305 if(textureMesh->tex_materials.size()>1)
3309 std::map<int, cv::Mat>(),
3310 std::map<
int, std::vector<CameraModel> >(),
3315 textureVertexToPixels,
3328 textureMesh->tex_coordinates,
3330 QMessageBox::information(
this, tr(
"Update Optimized Textured Mesh"), tr(
"Updated!"));
3331 ui_->actionView_optimized_mesh->setEnabled(
true);
3332 ui_->actionExport_optimized_mesh->setEnabled(
true);
3335 else if(meshes.size())
3338 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(1);
3341 QMessageBox::information(
this, tr(
"Update Optimized Mesh"), tr(
"Updated!"));
3342 ui_->actionView_optimized_mesh->setEnabled(
true);
3343 ui_->actionExport_optimized_mesh->setEnabled(
true);
3346 else if(clouds.size())
3350 QMessageBox::information(
this, tr(
"Update Optimized PointCloud"), tr(
"Updated!"));
3351 ui_->actionView_optimized_mesh->setEnabled(
true);
3352 ui_->actionExport_optimized_mesh->setEnabled(
true);
3357 QMessageBox::critical(
this, tr(
"Update Optimized Mesh"), tr(
"Nothing to save!"));
3364 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
3372 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"A database must must loaded first...\nUse File->Open database."));
3376 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save File"),
pathDatabase_+
"/Graph.dot", tr(
"Graphiz file (*.dot)"));
3387 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
3391 int id = QInputDialog::getInt(
this, tr(
"Around which location?"), tr(
"Location ID"),
ids_.first(),
ids_.first(),
ids_.last(), 1, &ok);
3395 int margin = QInputDialog::getInt(
this, tr(
"Depth around the location?"), tr(
"Margin"), 4, 1, 100, 1, &ok);
3398 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save File"),
pathDatabase_+
"/Graph" + QString::number(
id) +
".dot", tr(
"Graphiz file (*.dot)"));
3399 if(!path.isEmpty() &&
id>0)
3401 std::map<int, int> ids;
3402 std::list<int> curentMarginList;
3403 std::set<int> currentMargin;
3404 std::set<int> nextMargin;
3405 nextMargin.insert(
id);
3407 while((margin == 0 || m < margin) && nextMargin.size())
3409 curentMarginList = std::list<int>(nextMargin.rbegin(), nextMargin.rend());
3412 for(std::list<int>::iterator jter = curentMarginList.begin(); jter!=curentMarginList.end(); ++jter)
3414 if(ids.find(*jter) == ids.end())
3416 std::multimap<int, Link> links;
3417 ids.insert(std::pair<int, int>(*jter, m));
3423 for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
3431 nextMargin.insert(iter->first);
3436 if(currentMargin.insert(iter->first).second)
3438 curentMarginList.push_back(iter->first);
3450 ids.insert(std::pair<int,int>(
id, 0));
3451 std::set<int> idsSet;
3452 for(std::map<int, int>::iterator iter = ids.begin(); iter!=ids.end(); ++iter)
3454 idsSet.insert(idsSet.end(), iter->first);
3455 UINFO(
"Node %d", iter->first);
3457 UINFO(
"idsSet=%d", idsSet.size());
3462 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for signature %1.").arg(
id));
3478 progressDialog.show();
3482 plot->setWindowFlags(Qt::Window);
3483 plot->setWindowTitle(
"Local Occupancy Grid Generation Time (ms)");
3484 plot->setAttribute(Qt::WA_DeleteOnClose);
3490 plotCells->setWindowFlags(Qt::Window);
3491 plotCells->setWindowTitle(
"Occupancy Cells");
3492 plotCells->setAttribute(Qt::WA_DeleteOnClose);
3499 double decompressionTime = 0;
3500 double gridCreationTime = 0;
3502 for(
int i =0; i<
ids_.size() && !progressDialog.
isCanceled(); ++i)
3508 decompressionTime = timer.
ticks()*1000.0;
3515 std::vector<float> velocity;
3518 if(
dbDriver_->
getNodeInfo(data.
id(), odomPose, mapId, weight, label, stamp, groundTruth, velocity, gps, sensors))
3522 cv::Mat ground, obstacles, empty;
3523 cv::Point3f viewpoint;
3543 viewpoint.x += t.
x();
3544 viewpoint.y += t.
y();
3545 viewpoint.z += t.
z();
3559 viewpoint = cv::Point3f(t.
x(), t.
y(), t.
z());
3567 grid.createLocalMap(s, ground, obstacles, empty, viewpoint);
3570 gridCreationTime = timer.
ticks()*1000.0;
3573 msg = QString(
"Generated local occupancy grid map %1/%2").arg(i+1).arg((
int)
ids_.size());
3575 totalCurve->
addValue(
ids_.at(i), obstacles.cols+ground.cols+empty.cols);
3584 decompressionCurve->
addValue(
ids_.at(i), decompressionTime);
3585 gridCreationCurve->
addValue(
ids_.at(i), gridCreationTime);
3587 if(
ids_.size() < 50 || (i+1) % 25 == 0)
3589 QApplication::processEvents();
3610 if(
ids_.size() == 0)
3612 UWARN(
"ids_ is empty!");
3617 idsSet.insert(
ids_.at(
ui_->horizontalSlider_A->value()));
3618 idsSet.insert(
ids_.at(
ui_->horizontalSlider_B->value()));
3619 QList<int> ids = idsSet.toList();
3623 progressDialog.show();
3625 for(
int i =0; i<ids.size(); ++i)
3639 std::vector<float> velocity;
3642 if(
dbDriver_->
getNodeInfo(data.
id(), odomPose, mapId, weight, label, stamp, groundTruth, velocity, gps, sensors))
3646 cv::Mat ground, obstacles, empty;
3647 cv::Point3f viewpoint;
3666 viewpoint.x += t.
x();
3667 viewpoint.y += t.
y();
3668 viewpoint.z += t.
z();
3682 viewpoint = cv::Point3f(t.
x(), t.
y(), t.
z());
3690 grid.createLocalMap(s, ground, obstacles, empty, viewpoint);
3696 msg = QString(
"Generated local occupancy grid map %1/%2 (%3s)").arg(i+1).arg((
int)ids.size()).arg(time.
ticks());
3701 QApplication::processEvents();
3720 QMessageBox::warning(
this, tr(
"Cannot view 3D map"), tr(
"The database is empty..."));
3727 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3729 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3734 std::map<int, Transform> optimizedPoses;
3743 if(
ui_->groupBox_posefiltering->isChecked())
3746 ui_->doubleSpinBox_posefilteringRadius->value(),
3747 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
3749 if(optimizedPoses.size() > 0)
3755 QMap<int, Signature>(),
3756 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
3757 std::map<int, LaserScan>(),
3759 ui_->parameters_toolbox->getParameters());
3763 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
3771 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
3778 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3780 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3785 std::map<int, Transform> optimizedPoses;
3794 if(
ui_->groupBox_posefiltering->isChecked())
3797 ui_->doubleSpinBox_posefilteringRadius->value(),
3798 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
3800 if(optimizedPoses.size() > 0)
3806 QMap<int, Signature>(),
3807 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
3808 std::map<int, LaserScan>(),
3810 ui_->parameters_toolbox->getParameters());
3814 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
3823 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3825 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3830 const std::map<int, Transform> & optimizedPoses =
graphes_.back();
3833 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
3836 progressDialog->setMinimumWidth(800);
3837 progressDialog->show();
3839 const ParametersMap & parameters =
ui_->parameters_toolbox->getParameters();
3840 bool loopCovLimited = Parameters::defaultRGBDLoopCovLimited();
3841 Parameters::parse(parameters, Parameters::kRGBDLoopCovLimited(), loopCovLimited);
3847 int iterations =
ui_->spinBox_detectMore_iterations->value();
3850 std::multimap<int, int> checkedLoopClosures;
3851 std::pair<int, int> lastAdded(0,0);
3852 bool intraSession =
ui_->checkBox_detectMore_intraSession->isChecked();
3853 bool interSession =
ui_->checkBox_detectMore_interSession->isChecked();
3854 if(!interSession && !intraSession)
3856 QMessageBox::warning(
this, tr(
"Cannot detect more loop closures"), tr(
"Intra and inter session parameters are disabled! Enable one or both."));
3859 for(
int n=0; n<iterations; ++n)
3861 UINFO(
"iteration %d/%d", n+1, iterations);
3863 std::map<int, Transform>(optimizedPoses.upper_bound(0), optimizedPoses.end()),
3864 ui_->doubleSpinBox_detectMore_radius->value(),
3865 ui_->doubleSpinBox_detectMore_angle->value()*CV_PI/180.0);
3868 progressDialog->
appendText(tr(
"Looking for more loop closures, clusters found %1 clusters.").arg(clusters.size()));
3869 QApplication::processEvents();
3875 std::set<int> addedLinks;
3877 for(std::multimap<int, int>::iterator iter=clusters.begin(); iter!= clusters.end() && !progressDialog->
isCanceled(); ++iter, ++i)
3879 int from = iter->first;
3880 int to = iter->second;
3883 from = iter->second;
3890 if((interSession && mapIdFrom != mapIdTo) ||
3891 (intraSession && mapIdFrom == mapIdTo))
3897 addedLinks.find(from) == addedLinks.end() &&
3898 addedLinks.find(to) == addedLinks.end())
3900 checkedLoopClosures.insert(std::make_pair(from, to));
3903 UINFO(
"Added new loop closure between %d and %d.", from, to);
3905 addedLinks.insert(from);
3906 addedLinks.insert(to);
3907 lastAdded.first = from;
3908 lastAdded.second = to;
3910 progressDialog->
appendText(tr(
"Detected loop closure %1->%2! (%3/%4)").arg(from).arg(to).arg(i+1).arg(clusters.size()));
3911 QApplication::processEvents();
3919 QApplication::processEvents();
3922 UINFO(
"Iteration %d/%d: added %d loop closures.", n+1, iterations, (
int)addedLinks.size()/2);
3923 progressDialog->
appendText(tr(
"Iteration %1/%2: Detected %3 loop closures!").arg(n+1).arg(iterations).arg(addedLinks.size()/2));
3924 if(addedLinks.size() == 0)
3937 UINFO(
"Total added %d loop closures.", added);
3939 progressDialog->
appendText(tr(
"Total new loop closures detected=%1").arg(added));
3957 double stddev = QInputDialog::getDouble(
this, tr(
"Linear error"), tr(
"Std deviation (m)"), 0.01, 0.0001, 9, 4, &ok);
3959 double linearVar = stddev*stddev;
3960 stddev = QInputDialog::getDouble(
this, tr(
"Angular error"), tr(
"Std deviation (deg)"), 1, 0.01, 45, 2, &ok)*
M_PI/180.0;
3962 double angularVar = stddev*stddev;
3965 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
3968 progressDialog->setMinimumWidth(800);
3969 progressDialog->show();
3971 cv::Mat infMatrix = cv::Mat::eye(6,6,CV_64FC1);
3972 infMatrix(cv::Range(0,3), cv::Range(0,3))/=linearVar;
3973 infMatrix(cv::Range(3,6), cv::Range(3,6))/=angularVar;
3975 for(
int i=0; i<links.size(); ++i)
3977 int from = links[i].from();
3978 int to = links[i].to();
3983 UERROR(
"Not found link! (%d->%d)", from, to);
3993 bool updated =
false;
3994 std::multimap<int, Link>::iterator iter =
linksRefined_.find(currentLink.
from());
3997 if(iter->second.to() == currentLink.
to() &&
3998 iter->second.type() == currentLink.
type())
4000 iter->second = currentLink;
4011 progressDialog->
appendText(tr(
"Updated link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(links.size()));
4013 QApplication::processEvents();
4022 progressDialog->
appendText(
"Refining links finished!");
4039 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
4042 progressDialog->setMinimumWidth(800);
4043 progressDialog->show();
4045 for(
int i=0; i<links.size(); ++i)
4047 int from = links[i].from();
4048 int to = links[i].to();
4051 progressDialog->
appendText(tr(
"Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(links.size()));
4053 QApplication::processEvents();
4062 progressDialog->
appendText(
"Refining links finished!");
4068 if(QMessageBox::question(
this,
4069 tr(
"Reset all changes"),
4070 tr(
"You are about to reset all changes you've made so far, do you want to continue?"),
4071 QMessageBox::Yes | QMessageBox::No,
4072 QMessageBox::No) == QMessageBox::Yes)
4089 ui_->label_parentsA,
4090 ui_->label_childrenA,
4094 ui_->graphicsView_A,
4101 ui_->label_gravityA,
4103 ui_->label_sensorsA,
4111 ui_->label_parentsB,
4112 ui_->label_childrenB,
4116 ui_->graphicsView_B,
4123 ui_->label_gravityB,
4125 ui_->label_sensorsB,
4130 QLabel * labelIndex,
4131 QLabel * labelParents,
4132 QLabel * labelChildren,
4138 QLabel * labelMapId,
4140 QLabel * labelVelocity,
4141 QLabel * labelCalib,
4143 QLabel * labelGravity,
4145 QLabel * labelSensors,
4151 labelIndex->setText(QString::number(value));
4152 labelParents->clear();
4153 labelChildren->clear();
4156 labelMapId->clear();
4158 labelVelocity->clear();
4160 labelCalib->clear();
4161 labelScan ->clear();
4162 labelGravity->clear();
4164 labelSensors->clear();
4165 if(value >= 0 && value <
ids_.size())
4168 int id =
ids_.at(value);
4170 labelId->setText(QString::number(
id));
4190 if(
ui_->spinBox_mesh_fillDepthHoles->value() > 0)
4209 if(!imgDepth.empty())
4214 rect.setWidth(imgDepth.cols);
4215 rect.setHeight(imgDepth.rows);
4229 std::list<Signature*> signatures;
4232 if(signatures.size() && signatures.front()!=0 && !signatures.front()->getWordsKpts().empty())
4234 std::multimap<int, cv::KeyPoint> keypoints;
4235 for(std::map<int, int>::const_iterator iter=signatures.front()->getWords().begin(); iter!=signatures.front()->getWords().end(); ++iter)
4237 keypoints.insert(std::make_pair(iter->first, signatures.front()->getWordsKpts()[iter->second]));
4246 std::vector<float> v;
4252 label->setText(l.c_str());
4255 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));
4258 labelPose->setText(labelPose->text() +
"\n<Not in graph>");
4262 stamp->setText(QString::number(s,
'f'));
4263 stamp->setToolTip(QDateTime::fromMSecsSinceEpoch(s*1000.0).toString(
"dd.MM.yyyy hh:mm:ss.zzz"));
4267 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]));
4270 std::multimap<int, Link> gravityLink;
4272 if(!gravityLink.empty())
4275 gravityLink.begin()->second.transform().getEulerAngles(roll, pitch, yaw);
4276 Eigen::Vector3d v =
Transform(0,0,0,roll,pitch,0).
toEigen3d() * -Eigen::Vector3d::UnitZ();
4277 labelGravity->setText(QString(
"x=%1 y=%2 z=%3").arg(v[0]).arg(v[1]).arg(v[2]));
4278 labelGravity->setToolTip(QString(
"roll=%1 pitch=%2 yaw=%3").arg(roll).arg(pitch).arg(yaw));
4283 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()));
4284 labelGps->setToolTip(QDateTime::fromMSecsSinceEpoch(gps.
stamp()*1000.0).toString(
"dd.MM.yyyy hh:mm:ss.zzz"));
4290 for(EnvSensors::iterator iter=sensors.begin(); iter!=sensors.end(); ++iter)
4292 if(iter != sensors.begin())
4294 sensorsStr +=
" | ";
4295 tooltipStr +=
" | ";
4300 sensorsStr +=
uFormat(
"%.1f dbm", iter->second.value()).c_str();
4301 tooltipStr +=
"Wifi signal strength";
4305 sensorsStr +=
uFormat(
"%.1f \u00B0C", iter->second.value()).c_str();
4306 tooltipStr +=
"Ambient Temperature";
4310 sensorsStr +=
uFormat(
"%.1f hPa", iter->second.value()).c_str();
4311 tooltipStr +=
"Ambient Air Pressure";
4315 sensorsStr +=
uFormat(
"%.0f lx", iter->second.value()).c_str();
4316 tooltipStr +=
"Ambient Light";
4320 sensorsStr +=
uFormat(
"%.0f %%", iter->second.value()).c_str();
4321 tooltipStr +=
"Ambient Relative Humidity";
4325 sensorsStr +=
uFormat(
"%.2f", iter->second.value()).c_str();
4326 tooltipStr += QString(
"Type %1").arg((
int)iter->first);
4330 labelSensors->setText(sensorsStr);
4331 labelSensors->setToolTip(tooltipStr);
4335 std::stringstream calibrationDetails;
4340 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]")
4350 .arg(data.
cameraModels()[0].localTransform().prettyPrint().c_str())
4357 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]")
4365 .arg(data.
cameraModels()[0].localTransform().prettyPrint().c_str())
4371 for(
unsigned int i=0; i<data.
cameraModels().size();++i)
4373 if(i!=0) calibrationDetails << std::endl;
4374 calibrationDetails <<
"Id: " << i <<
" Size=" << data.
cameraModels()[i].imageWidth() <<
"x" << data.
cameraModels()[i].imageHeight() << std::endl;
4375 if( data.
cameraModels()[i].K_raw().total()) calibrationDetails <<
"K=" << data.
cameraModels()[i].K_raw() << std::endl;
4376 if( data.
cameraModels()[i].D_raw().total()) calibrationDetails <<
"D=" << data.
cameraModels()[i].D_raw() << std::endl;
4385 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]")
4403 calibrationDetails << std::endl;
4409 calibrationDetails << std::endl;
4415 labelCalib->setToolTip(calibrationDetails.str().c_str());
4420 labelCalib->setText(
"NA");
4425 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]")
4448 ui_->graphicsView_stereo->clear();
4455 if(signatures.size() &&
ui_->checkBox_odomFrame_3dview->isChecked())
4458 (*signatures.begin())->getPose().getTranslationAndEulerAngles(x, y, z, roll, pitch, yaw);
4472 if(
ui_->checkBox_showCloud->isChecked() ||
ui_->checkBox_showMesh->isChecked())
4478 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
4479 pcl::IndicesPtr indices(
new std::vector<int>);
4483 if(
ui_->spinBox_mesh_fillDepthHoles->value() > 0)
4491 ui_->spinBox_decimation->value(),0,0,indices.get());
4504 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
4509 if(
ui_->checkBox_showMesh->isChecked() && !cloud->is_dense)
4511 Eigen::Vector3f viewpoint(0.0
f,0.0
f,0.0
f);
4514 viewpoint[0] = data.
cameraModels()[0].localTransform().x();
4515 viewpoint[1] = data.
cameraModels()[0].localTransform().y();
4516 viewpoint[2] = data.
cameraModels()[0].localTransform().z();
4526 float(
ui_->spinBox_mesh_angleTolerance->value())*
M_PI/180.0
f,
4527 ui_->checkBox_mesh_quad->isChecked(),
4528 ui_->spinBox_mesh_triangleSize->value(),
4531 if(
ui_->spinBox_mesh_minClusterSize->value())
4534 std::vector<std::set<int> > neighbors;
4535 std::vector<std::set<int> > vertexToPolygons;
4542 ui_->spinBox_mesh_minClusterSize->value());
4543 std::vector<pcl::Vertices> filteredPolygons(polygons.size());
4545 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
4547 for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
4549 filteredPolygons[oi++] = polygons.at(*jter);
4552 filteredPolygons.resize(oi);
4553 polygons = filteredPolygons;
4558 if(
ui_->checkBox_showCloud->isChecked())
4564 else if(
ui_->checkBox_showCloud->isChecked())
4566 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
4567 pcl::IndicesPtr indices(
new std::vector<int>);
4571 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
4596 if(
ui_->checkBox_showWords->isChecked() &&
4597 !signatures.empty() &&
4598 !(*signatures.begin())->getWords3().empty())
4600 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
4601 cloud->resize((*signatures.begin())->getWords3().size());
4603 for(std::multimap<int, int>::const_iterator iter=(*signatures.begin())->getWords().begin();
4604 iter!=(*signatures.begin())->getWords().end();
4607 const cv::Point3f & pt = (*signatures.begin())->getWords3()[iter->second];
4608 cloud->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
4628 if(
ui_->checkBox_showScan->isChecked() && laserScanRaw.
size())
4645 else if(laserScanRaw.
hasRGB())
4658 if(
ui_->checkBox_showMap->isChecked() ||
ui_->checkBox_showGrid->isChecked())
4660 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> > localMaps;
4661 std::map<int, std::pair<float, cv::Point3f> > localMapsInfo;
4672 if(!localMaps.empty())
4674 std::map<int, Transform> poses;
4675 poses.insert(std::make_pair(data.
id(), pose));
4677 #ifdef RTABMAP_OCTOMAP 4679 if(
ui_->checkBox_octomap->isChecked() &&
4680 (!localMaps.begin()->second.first.first.empty() || !localMaps.begin()->second.first.second.empty()) &&
4681 (localMaps.begin()->second.first.first.empty() || localMaps.begin()->second.first.first.channels() > 2) &&
4682 (localMaps.begin()->second.first.second.empty() || localMaps.begin()->second.first.second.channels() > 2) &&
4683 (localMaps.begin()->second.second.empty() || localMaps.begin()->second.second.channels() > 2) &&
4684 localMapsInfo.begin()->second.first > 0.0f)
4687 octomap =
new OctoMap(localMapsInfo.begin()->second.first);
4688 octomap->
addToCache(data.
id(), localMaps.begin()->second.first.first, localMaps.begin()->second.first.second, localMaps.begin()->second.second, localMapsInfo.begin()->second.second);
4693 if(
ui_->checkBox_showMap->isChecked())
4695 float xMin=0.0f, yMin=0.0f;
4698 float gridCellSize = Parameters::defaultGridCellSize();
4700 #ifdef RTABMAP_OCTOMAP 4710 grid.addToCache(data.
id(), localMaps.begin()->second.first.first, localMaps.begin()->second.first.second, localMaps.begin()->second.second);
4712 map8S = grid.getMap(xMin, yMin);
4721 if(
ui_->checkBox_showGrid->isChecked())
4723 #ifdef RTABMAP_OCTOMAP 4726 if(
ui_->comboBox_octomap_rendering_type->currentIndex()== 0)
4728 pcl::IndicesPtr obstacles(
new std::vector<int>);
4729 pcl::IndicesPtr empty(
new std::vector<int>);
4730 pcl::IndicesPtr ground(
new std::vector<int>);
4731 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap->
createCloud(
ui_->spinBox_grid_depth->value(), obstacles.get(), empty.get(), ground.get());
4734 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
4735 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
4739 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
4740 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
4746 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZ>);
4747 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
4751 pcl::PointCloud<pcl::PointXYZ>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZ>);
4752 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
4757 if(
ui_->checkBox_grid_empty->isChecked())
4759 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZ>);
4760 pcl::copyPointCloud(*cloud, *empty, *emptyCloud);
4797 if(
ui_->checkBox_grid_empty->isChecked())
4802 QColor(
ui_->lineEdit_emptyColor->text()));
4808 #ifdef RTABMAP_OCTOMAP 4819 if(signatures.size())
4821 UASSERT(signatures.front() != 0 && signatures.size() == 1);
4822 delete signatures.front();
4828 std::multimap<int, rtabmap::Link> links;
4832 QString strParents, strChildren;
4833 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
4838 if(iter->first <
id)
4840 strChildren.append(QString(
"%1 ").arg(iter->first));
4844 strParents.append(QString(
"%1 ").arg(iter->first));
4848 labelParents->setText(strParents);
4849 labelChildren->setText(strChildren);
4855 labelMapId->setText(QString::number(mapId));
4866 if(updateConstraintView &&
ui_->dockWidget_constraints->isVisible())
4869 int from =
ids_.at(
ui_->horizontalSlider_A->value());
4870 int to =
ids_.at(
ui_->horizontalSlider_B->value());
4879 if(i !=
ui_->horizontalSlider_loops->value())
4881 ui_->horizontalSlider_loops->blockSignals(
true);
4882 ui_->horizontalSlider_loops->setValue(i);
4883 ui_->horizontalSlider_loops->blockSignals(
false);
4886 ui_->horizontalSlider_neighbors->blockSignals(
true);
4887 ui_->horizontalSlider_neighbors->setValue(0);
4888 ui_->horizontalSlider_neighbors->blockSignals(
false);
4898 if(i !=
ui_->horizontalSlider_neighbors->value())
4900 ui_->horizontalSlider_neighbors->blockSignals(
true);
4901 ui_->horizontalSlider_neighbors->setValue(i);
4902 ui_->horizontalSlider_neighbors->blockSignals(
false);
4905 ui_->horizontalSlider_loops->blockSignals(
true);
4906 ui_->horizontalSlider_loops->setValue(0);
4907 ui_->horizontalSlider_loops->blockSignals(
false);
4915 ui_->horizontalSlider_loops->blockSignals(
true);
4916 ui_->horizontalSlider_neighbors->blockSignals(
true);
4917 ui_->horizontalSlider_loops->setValue(0);
4918 ui_->horizontalSlider_neighbors->setValue(0);
4919 ui_->horizontalSlider_loops->blockSignals(
false);
4920 ui_->horizontalSlider_neighbors->blockSignals(
false);
4925 bool constraintViewUpdated =
false;
4929 constraintViewUpdated =
true;
4934 std::map<int, Transform> optimizedPoses =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
4935 if(optimizedPoses.size() > 0)
4937 std::map<int, Transform>::iterator fromIter = optimizedPoses.find(from);
4938 std::map<int, Transform>::iterator toIter = optimizedPoses.find(to);
4939 if(fromIter != optimizedPoses.end() &&
4940 toIter != optimizedPoses.end())
4942 Link link(from, to,
Link::kUndef, fromIter->second.inverse() * toIter->second);
4944 constraintViewUpdated =
true;
4948 if(!constraintViewUpdated)
4950 ui_->label_constraint->clear();
4951 ui_->label_constraint_opt->clear();
4952 ui_->label_variance->clear();
4953 ui_->lineEdit_covariance->clear();
4954 ui_->label_type->clear();
4955 ui_->label_type_name->clear();
4956 ui_->checkBox_showOptimized->setEnabled(
false);
4966 if(this->parent() == 0)
4974 if(
ui_->horizontalSlider_A->maximum())
4976 int id =
ids_.at(
ui_->horizontalSlider_A->value());
4987 ui_->dockWidget_stereoView->isVisible() &&
4994 if(data->
imageRaw().channels() == 3)
4996 cv::cvtColor(data->
imageRaw(), leftMono, CV_BGR2GRAY);
5008 std::vector<cv::KeyPoint> kpts;
5009 uInsert(parameters,
ParametersPair(Parameters::kKpMaxFeatures(), parameters.at(Parameters::kVisMaxFeatures())));
5010 uInsert(parameters,
ParametersPair(Parameters::kKpMinDepth(), parameters.at(Parameters::kVisMinDepth())));
5011 uInsert(parameters,
ParametersPair(Parameters::kKpMaxDepth(), parameters.at(Parameters::kVisMaxDepth())));
5012 uInsert(parameters,
ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kVisFeatureType())));
5013 uInsert(parameters,
ParametersPair(Parameters::kKpRoiRatios(), parameters.at(Parameters::kVisRoiRatios())));
5014 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixEps(), parameters.at(Parameters::kVisSubPixEps())));
5015 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixIterations(), parameters.at(Parameters::kVisSubPixIterations())));
5016 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixWinSize(), parameters.at(Parameters::kVisSubPixWinSize())));
5021 float timeKpt = timer.
ticks();
5023 std::vector<cv::Point2f> leftCorners;
5024 cv::KeyPoint::convert(kpts, leftCorners);
5027 std::vector<unsigned char> status;
5028 std::vector<cv::Point2f> rightCorners;
5037 float timeStereo = timer.
ticks();
5039 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
5040 cloud->resize(kpts.size());
5041 float bad_point = std::numeric_limits<float>::quiet_NaN ();
5042 UASSERT(status.size() == kpts.size());
5045 int flowOutliers= 0;
5046 int slopeOutliers= 0;
5047 int negativeDisparityOutliers = 0;
5048 for(
unsigned int i=0; i<status.size(); ++i)
5050 cv::Point3f pt(bad_point, bad_point, bad_point);
5053 float disparity = leftCorners[i].x - rightCorners[i].x;
5054 if(disparity > 0.0
f)
5066 cloud->at(oi++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
5072 ++negativeDisparityOutliers;
5082 UINFO(
"correspondences = %d/%d (%f) (time kpt=%fs stereo=%fs)",
5083 (
int)cloud->size(), (int)leftCorners.size(), float(cloud->size())/
float(leftCorners.size()), timeKpt, timeStereo);
5089 ui_->label_stereo_inliers->setNum(inliers);
5090 ui_->label_stereo_flowOutliers->setNum(flowOutliers);
5091 ui_->label_stereo_slopeOutliers->setNum(slopeOutliers);
5092 ui_->label_stereo_disparityOutliers->setNum(negativeDisparityOutliers);
5094 std::vector<cv::KeyPoint> rightKpts;
5095 cv::KeyPoint::convert(rightCorners, rightKpts);
5096 std::vector<cv::DMatch> good_matches(kpts.size());
5097 for(
unsigned int i=0; i<good_matches.size(); ++i)
5099 good_matches[i].trainIdx = i;
5100 good_matches[i].queryIdx = i;
5112 ui_->graphicsView_stereo->clear();
5113 ui_->graphicsView_stereo->setLinesShown(
true);
5114 ui_->graphicsView_stereo->setFeaturesShown(
false);
5115 ui_->graphicsView_stereo->setImageDepthShown(
true);
5121 for(
unsigned int i=0; i<kpts.size(); ++i)
5123 if(rightKpts[i].pt.x > 0 && rightKpts[i].pt.y > 0)
5125 QColor c = Qt::green;
5130 else if(status[i] == 100)
5134 else if(status[i] == 101)
5138 else if(status[i] == 102)
5142 else if(status[i] == 110)
5146 ui_->graphicsView_stereo->addLine(
5152 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));
5155 ui_->graphicsView_stereo->update();
5161 int from =
ids_.at(
ui_->horizontalSlider_A->value());
5162 int to =
ids_.at(
ui_->horizontalSlider_B->value());
5165 ui_->graphicsView_A->clearLines();
5166 ui_->graphicsView_A->setFeaturesColor(
ui_->graphicsView_A->getDefaultFeatureColor());
5167 ui_->graphicsView_B->clearLines();
5168 ui_->graphicsView_B->setFeaturesColor(
ui_->graphicsView_B->getDefaultFeatureColor());
5170 const QMultiMap<int, KeypointItem*> & wordsA =
ui_->graphicsView_A->getFeatures();
5171 const QMultiMap<int, KeypointItem*> & wordsB =
ui_->graphicsView_B->getFeatures();
5172 std::set<int> inliersSet(inliers.begin(), inliers.end());
5173 if(wordsA.size() && wordsB.size())
5175 QList<int> ids = wordsA.uniqueKeys();
5176 for(
int i=0; i<ids.size(); ++i)
5178 if(ids[i] > 0 && wordsA.count(ids[i]) == 1 && wordsB.count(ids[i]) == 1)
5182 float scaleAX =
ui_->graphicsView_A->viewScale();
5183 float scaleBX =
ui_->graphicsView_B->viewScale();
5185 float scaleDiff =
ui_->graphicsView_A->viewScale() /
ui_->graphicsView_B->viewScale();
5189 if(
ui_->actionVertical_Layout->isChecked())
5191 deltaAY =
ui_->graphicsView_A->height()/scaleAX;
5195 deltaAX =
ui_->graphicsView_A->width()/scaleAX;
5200 if(
ui_->actionVertical_Layout->isChecked())
5202 deltaBY =
ui_->graphicsView_B->height()/scaleBX;
5206 deltaBX =
ui_->graphicsView_A->width()/scaleBX;
5212 QColor cA =
ui_->graphicsView_A->getDefaultMatchingLineColor();
5213 QColor cB =
ui_->graphicsView_B->getDefaultMatchingLineColor();
5214 if(inliersSet.find(ids[i])!=inliersSet.end())
5216 cA =
ui_->graphicsView_A->getDefaultMatchingFeatureColor();
5217 cB =
ui_->graphicsView_B->getDefaultMatchingFeatureColor();
5218 ui_->graphicsView_A->setFeatureColor(ids[i],
ui_->graphicsView_A->getDefaultMatchingFeatureColor());
5219 ui_->graphicsView_B->setFeatureColor(ids[i],
ui_->graphicsView_B->getDefaultMatchingFeatureColor());
5223 ui_->graphicsView_A->setFeatureColor(ids[i],
ui_->graphicsView_A->getDefaultMatchingLineColor());
5224 ui_->graphicsView_B->setFeatureColor(ids[i],
ui_->graphicsView_B->getDefaultMatchingLineColor());
5227 ui_->graphicsView_A->addLine(
5228 kptA->rect().x()+kptA->rect().width()/2,
5229 kptA->rect().y()+kptA->rect().height()/2,
5230 kptB->rect().x()/scaleDiff+kptB->rect().width()/scaleDiff/2+deltaAX,
5231 kptB->rect().y()/scaleDiff+kptB->rect().height()/scaleDiff/2+deltaAY,
5234 ui_->graphicsView_B->addLine(
5235 kptA->rect().x()*scaleDiff+kptA->rect().width()*scaleDiff/2-deltaBX,
5236 kptA->rect().y()*scaleDiff+kptA->rect().height()*scaleDiff/2-deltaBY,
5237 kptB->rect().x()+kptB->rect().width()/2,
5238 kptB->rect().y()+kptB->rect().height()/2,
5242 ui_->graphicsView_A->update();
5243 ui_->graphicsView_B->update();
5250 ui_->label_indexA->setText(QString::number(value));
5251 if(value>=0 && value <
ids_.size())
5253 ui_->label_idA->setText(QString::number(
ids_.at(value)));
5263 ui_->label_indexB->setText(QString::number(value));
5264 if(value>=0 && value <
ids_.size())
5266 ui_->label_idB->setText(QString::number(
ids_.at(value)));
5276 if(
ui_->dockWidget_view3d->isVisible())
5312 cv::Mat covBefore = link.
infMatrix().inv();
5314 covBefore.at<
double>(0,0)!=1.0?
std::sqrt(covBefore.at<
double>(0,0)):0,
5315 covBefore.at<
double>(5,5)!=1.0?
std::sqrt(covBefore.at<
double>(5,5)):0);
5316 if(dialog.exec() == QDialog::Accepted)
5318 bool updated =
false;
5319 cv::Mat covariance = cv::Mat::eye(6, 6, CV_64FC1);
5320 if(dialog.getLinearVariance()>0)
5322 covariance(cv::Range(0,3), cv::Range(0,3)) *= dialog.getLinearVariance()*dialog.getLinearVariance();
5324 if(dialog.getAngularVariance()>0)
5326 covariance(cv::Range(3,6), cv::Range(3,6)) *= dialog.getAngularVariance()*dialog.getAngularVariance();
5328 Link newLink(link.
from(), link.
to(), link.
type(), dialog.getTransform(), covariance.inv());
5332 if(iter->second.to() == link.
to() &&
5333 iter->second.type() == link.
type())
5335 iter->second = newLink;
5343 linksRefined_.insert(std::make_pair(newLink.from(), newLink));
5356 if(dialog.exec() == QDialog::Accepted)
5358 cv::Mat covariance = cv::Mat::eye(6, 6, CV_64FC1);
5367 int from =
ids_.at(
ui_->horizontalSlider_A->value());
5368 int to =
ids_.at(
ui_->horizontalSlider_B->value());
5375 if(newLink.from() < newLink.to())
5379 linksAdded_.insert(std::make_pair(newLink.from(), newLink));
5398 ui_->horizontalSlider_neighbors->value() >= 0 &&
ui_->horizontalSlider_neighbors->value() <
neighborLinks_.size())
5403 ui_->horizontalSlider_loops->value() >= 0 &&
ui_->horizontalSlider_loops->value() <
loopLinks_.size())
5417 bool updateImageSliders,
5427 if(iterLink->second.from() == link.to())
5429 link = iterLink->second.
inverse();
5433 link = iterLink->second;
5436 else if(
ui_->checkBox_ignorePoseCorrection->isChecked())
5443 if(!poseFrom.
isNull() && !poseTo.isNull())
5447 link =
Link(link.from(),
5454 UDEBUG(
"%d -> %d", link.from(), link.to());
5460 t.getEulerAngles(roll, pitch, yaw);
5464 ui_->label_constraint->clear();
5465 ui_->label_constraint_opt->clear();
5466 ui_->checkBox_showOptimized->setEnabled(
false);
5469 ui_->label_type->setText(QString::number(link.type()));
5470 ui_->label_type_name->setText(tr(
"(%1)")
5480 ui_->label_variance->setText(QString(
"%1, %2")
5481 .arg(
sqrt(link.transVariance()))
5482 .arg(
sqrt(link.rotVariance())));
5483 std::stringstream out;
5484 out << link.infMatrix().inv();
5485 ui_->lineEdit_covariance->setText(out.str().c_str());
5486 ui_->label_constraint->setText(QString(
"%1").arg(t.prettyPrint().c_str()).replace(
" ",
"\n"));
5488 (int)
graphes_.size()-1 ==
ui_->horizontalSlider_iterations->maximum())
5490 std::map<int, rtabmap::Transform> & graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
5492 std::map<int, rtabmap::Transform>::iterator iterFrom = graph.find(link.from());
5493 std::map<int, rtabmap::Transform>::iterator iterTo = graph.find(link.to());
5494 if(iterFrom != graph.end() && iterTo != graph.end())
5496 ui_->checkBox_showOptimized->setEnabled(
true);
5501 float a = pcl::getAngle3D(Eigen::Vector4f(v1.
x(), v1.
y(), v1.
z(), 0), Eigen::Vector4f(v2.
x(), v2.
y(), v2.
z(), 0));
5502 a = (a *180.0f) / CV_PI;
5503 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));
5505 if(
ui_->checkBox_showOptimized->isChecked())
5512 if(updateImageSliders)
5514 ui_->horizontalSlider_A->blockSignals(
true);
5515 ui_->horizontalSlider_B->blockSignals(
true);
5518 ui_->horizontalSlider_A->setValue(
idToIndex_.value(link.from()));
5520 ui_->horizontalSlider_B->setValue(
idToIndex_.value(link.to()));
5521 ui_->horizontalSlider_A->blockSignals(
false);
5522 ui_->horizontalSlider_B->blockSignals(
false);
5526 ui_->label_parentsA,
5527 ui_->label_childrenA,
5531 ui_->graphicsView_A,
5538 ui_->label_gravityA,
5540 ui_->label_sensorsA,
5546 ui_->label_parentsB,
5547 ui_->label_childrenB,
5551 ui_->graphicsView_B,
5558 ui_->label_gravityB,
5560 ui_->label_sensorsB,
5569 if(signatureFrom.
id()>0)
5581 if(signatureTo.
id()>0)
5585 else if(link.to()>0)
5595 if(
ui_->checkBox_odomFrame->isChecked())
5601 std::vector<float> v;
5617 if(
ui_->checkBox_show3Dclouds->isChecked())
5619 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFrom, cloudTo;
5620 pcl::IndicesPtr indicesFrom(
new std::vector<int>);
5621 pcl::IndicesPtr indicesTo(
new std::vector<int>);
5631 if(cloudTo.get() && indicesTo->size())
5637 if(
ui_->doubleSpinBox_gainCompensationRadius->value()>0.0 &&
5638 cloudFrom.get() && indicesFrom->size() &&
5639 cloudTo.get() && indicesTo->size())
5644 compensator.apply(0, cloudFrom, indicesFrom);
5645 compensator.apply(1, cloudTo, indicesTo);
5646 UINFO(
"Gain compensation time = %fs", t.
ticks());
5649 if(cloudFrom.get() && indicesFrom->size())
5651 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
5653 cloudFrom =
util3d::voxelize(cloudFrom, indicesFrom,
ui_->doubleSpinBox_voxelSize->value());
5657 if(cloudTo.get() && indicesTo->size())
5659 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
5669 if(
ui_->checkBox_show3DWords->isChecked())
5672 ids.push_back(link.from());
5675 ids.push_back(link.to());
5677 std::list<Signature*> signatures;
5679 if(signatures.size() == 2 || (link.to()<0 && signatures.size()==1))
5681 const Signature * sFrom = signatureFrom.
id()>0?&signatureFrom:signatures.front();
5683 if(signatures.size()==2)
5685 sTo = signatureTo.
id()>0?&signatureTo:signatures.back();
5689 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFrom(
new pcl::PointCloud<pcl::PointXYZ>);
5690 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTo(
new pcl::PointCloud<pcl::PointXYZ>);
5691 cloudFrom->resize(sFrom->
getWords3().size());
5694 cloudTo->resize(sTo->
getWords3().size());
5699 for(std::multimap<int, int>::const_iterator iter=sFrom->
getWords().begin();
5703 const cv::Point3f & pt = sFrom->
getWords3()[iter->second];
5704 cloudFrom->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
5710 for(std::multimap<int, int>::const_iterator iter=sTo->
getWords().begin();
5714 const cv::Point3f & pt = sTo->
getWords3()[iter->second];
5715 cloudTo->at(i++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
5719 if(cloudFrom->size())
5732 if(cloudFrom->size())
5738 UWARN(
"Empty 3D words for node %d", link.from());
5749 UWARN(
"Empty 3D words for node %d", link.to());
5756 UERROR(
"Not found signature %d or %d in RAM", link.from(), link.to());
5761 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
5771 if(
ui_->checkBox_show2DScans->isChecked())
5775 !link.userDataCompressed().empty() &&
5776 signatureTo.
id()==0)
5778 std::vector<int> ids;
5779 cv::Mat userData = link.uncompressUserDataConst();
5780 if(userData.type() == CV_8SC1 &&
5781 userData.rows == 1 &&
5782 userData.cols >= 8 &&
5783 userData.at<
char>(userData.cols-1) == 0 &&
5784 memcmp(userData.data,
"SCANS:", 6) == 0)
5786 std::string scansStr = (
const char *)userData.data;
5787 UINFO(
"Detected \"%s\" in links's user data", scansStr.c_str());
5788 if(!scansStr.empty())
5790 std::list<std::string> strs =
uSplit(scansStr,
':');
5791 if(strs.size() == 2)
5793 std::list<std::string> strIds =
uSplit(strs.rbegin()->c_str(),
';');
5794 for(std::list<std::string>::iterator iter=strIds.begin(); iter!=strIds.end(); ++iter)
5796 ids.push_back(atoi(iter->c_str()));
5797 if(ids.back() == link.from())
5810 std::map<int, rtabmap::Transform> poses;
5811 for(
unsigned int i=0; i<ids.size(); ++i)
5819 UERROR(
"Not found %d node!", ids[i]);
5827 std::map<int, rtabmap::Transform> posesOut;
5828 std::multimap<int, rtabmap::Link> linksOut;
5836 if(poses.size() != posesOut.size())
5838 UWARN(
"Scan poses input and output are different! %d vs %d", (
int)poses.size(), (int)posesOut.size());
5839 UWARN(
"Input poses: ");
5840 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
5842 UWARN(
" %d", iter->first);
5844 UWARN(
"Input links: ");
5846 for(std::multimap<int, Link>::iterator iter=modifiedLinks.begin(); iter!=modifiedLinks.end(); ++iter)
5848 UWARN(
" %d->%d", iter->second.from(), iter->second.to());
5855 std::map<int, rtabmap::Transform> finalPoses = optimizer->
optimize(link.to(), posesOut, linksOut);
5860 pcl::PointCloud<pcl::PointXYZ>::Ptr assembledScans(
new pcl::PointCloud<pcl::PointXYZ>);
5861 pcl::PointCloud<pcl::PointNormal>::Ptr assembledNormalScans(
new pcl::PointCloud<pcl::PointNormal>);
5862 pcl::PointCloud<pcl::PointXYZI>::Ptr assembledIScans(
new pcl::PointCloud<pcl::PointXYZI>);
5863 pcl::PointCloud<pcl::PointXYZINormal>::Ptr assembledINormalScans(
new pcl::PointCloud<pcl::PointXYZINormal>);
5864 pcl::PointCloud<pcl::PointXYZ>::Ptr graph(
new pcl::PointCloud<pcl::PointXYZ>);
5865 for(std::map<int, Transform>::iterator iter=finalPoses.begin(); iter!=finalPoses.end(); ++iter)
5867 iter->second = u * iter->second;
5868 if(iter->first != link.to())
5895 graph->push_back(
util3d::transformPoint(pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z()), pose));
5898 if(assembledNormalScans->size())
5903 if(assembledScans->size())
5908 if(assembledINormalScans->size())
5913 if(assembledIScans->size())
5933 pcl::PointCloud<pcl::PointXYZINormal>::Ptr scan;
5940 pcl::PointCloud<pcl::PointNormal>::Ptr scan;
5947 pcl::PointCloud<pcl::PointXYZI>::Ptr scan;
5954 pcl::PointCloud<pcl::PointXYZ>::Ptr scan;
5964 pcl::PointCloud<pcl::PointXYZINormal>::Ptr scan;
5971 pcl::PointCloud<pcl::PointNormal>::Ptr scan;
5978 pcl::PointCloud<pcl::PointXYZI>::Ptr scan;
5985 pcl::PointCloud<pcl::PointXYZ>::Ptr scan;
5995 #if PCL_VERSION_COMPARE(>=, 1, 7, 2) 6016 ui_->pushButton_refine->setEnabled(
false);
6017 ui_->pushButton_reset->setEnabled(
false);
6018 ui_->pushButton_add->setEnabled(
false);
6019 ui_->pushButton_reject->setEnabled(
false);
6020 ui_->toolButton_constraint->setEnabled(
false);
6024 ui_->pushButton_reject->setEnabled(
true);
6028 int from =
ids_.at(
ui_->horizontalSlider_A->value());
6029 int to =
ids_.at(
ui_->horizontalSlider_B->value());
6030 if(from!=to && from && to &&
6033 (
ui_->checkBox_enableForAll->isChecked() ||
6040 ui_->pushButton_add->setEnabled(
true);
6047 ((currentLink.
from() == from && currentLink.
to() == to) || (currentLink.
from() == to && currentLink.
to() == from)))
6051 ui_->pushButton_reject->setEnabled(
true);
6055 bool modified =
false;
6059 currentLink = iter->second;
6060 ui_->pushButton_reset->setEnabled(
true);
6065 ui_->pushButton_reset->setEnabled(
false);
6067 ui_->pushButton_refine->setEnabled(currentLink.
from()!=currentLink.
to());
6068 ui_->toolButton_constraint->setEnabled(
true);
6079 if(refPoses.empty())
6089 if(refPoses.size() == graph.size() && length >= 100.0f)
6094 UINFO(
"KITTI t_err = %f %%", t_err);
6095 UINFO(
"KITTI r_err = %f deg/m", r_err);
6098 float translational_rmse = 0.0f;
6099 float translational_mean = 0.0f;
6100 float translational_median = 0.0f;
6101 float translational_std = 0.0f;
6102 float translational_min = 0.0f;
6103 float translational_max = 0.0f;
6104 float rotational_rmse = 0.0f;
6105 float rotational_mean = 0.0f;
6106 float rotational_median = 0.0f;
6107 float rotational_std = 0.0f;
6108 float rotational_min = 0.0f;
6109 float rotational_max = 0.0f;
6116 translational_median,
6128 ui_->label_rmse->setNum(translational_rmse);
6129 UINFO(
"translational_rmse=%f", translational_rmse);
6130 UINFO(
"translational_mean=%f", translational_mean);
6131 UINFO(
"translational_median=%f", translational_median);
6132 UINFO(
"translational_std=%f", translational_std);
6133 UINFO(
"translational_min=%f", translational_min);
6134 UINFO(
"translational_max=%f", translational_max);
6136 UINFO(
"rotational_rmse=%f", rotational_rmse);
6137 UINFO(
"rotational_mean=%f", rotational_mean);
6138 UINFO(
"rotational_median=%f", rotational_median);
6139 UINFO(
"rotational_std=%f", rotational_std);
6140 UINFO(
"rotational_min=%f", rotational_min);
6141 UINFO(
"rotational_max=%f", rotational_max);
6143 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked() && !gtToMap.
isIdentity())
6145 for(std::map<int, Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
6147 iter->second = gtToMap * iter->second;
6152 std::map<int, rtabmap::Transform> graphFiltered;
6159 graphFiltered = graph;
6161 if(
ui_->groupBox_posefiltering->isChecked())
6164 ui_->doubleSpinBox_posefilteringRadius->value(),
6165 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
6167 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> > localMaps;
6168 std::map<int, std::pair<float, cv::Point3f> > localMapsInfo;
6169 #ifdef RTABMAP_OCTOMAP 6176 if(
ui_->dockWidget_graphView->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
6179 UINFO(
"Update local maps list...");
6180 std::vector<int> ids =
uKeys(graphFiltered);
6181 for(
unsigned int i=0; i<ids.size(); ++i)
6190 if(!
localMaps_.find(ids[i])->second.first.first.empty() || !
localMaps_.find(ids[i])->second.first.second.empty())
6192 localMaps.insert(*
localMaps_.find(ids.at(i)));
6200 cv::Mat ground, obstacles, empty;
6202 localMaps_.insert(std::make_pair(ids.at(i), std::make_pair(std::make_pair(ground, obstacles), empty)));
6204 if(!ground.empty() || !obstacles.empty())
6206 localMaps.insert(std::make_pair(ids.at(i), std::make_pair(std::make_pair(ground, obstacles), empty)));
6212 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=
localMaps_.begin(); iter!=
localMaps_.end();)
6214 if(graphFiltered.find(iter->first) == graphFiltered.end())
6224 UINFO(
"Update local maps list... done (%d local maps, graph size=%d)", (
int)localMaps.size(), (int)graph.size());
6228 float cellSize = Parameters::defaultGridCellSize();
6234 if(!
ui_->checkBox_wmState->isChecked())
6236 bool allNodesAreInWM =
true;
6237 std::map<int, float> colors;
6238 for(std::map<int, rtabmap::Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
6242 colors.insert(std::make_pair(iter->first, 1));
6246 allNodesAreInWM =
false;
6249 if(!allNodesAreInWM)
6251 ui_->graphViewer->updatePosterior(colors, 1, 1);
6254 ui_->graphViewer->clearMap();
6256 if(graph.size() && localMaps.size() &&
6257 (
ui_->graphViewer->isGridMapVisible() ||
ui_->dockWidget_occupancyGridView->isVisible()))
6262 #ifdef RTABMAP_OCTOMAP 6263 if(
ui_->checkBox_octomap->isChecked())
6266 bool updateAborted =
false;
6267 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
6269 if(iter->second.first.first.channels() == 2 || iter->second.first.second.channels() == 2)
6271 QMessageBox::warning(
this, tr(
""),
6272 tr(
"Some local occupancy grids are 2D, but OctoMap requires 3D local " 6273 "occupancy grids. Uncheck OctoMap under GUI parameters or generate " 6274 "3D local occupancy grids (\"Grid/3D\" core parameter)."));
6275 updateAborted =
true;
6278 octomap_->
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second, localMapsInfo.at(iter->first).second);
6288 if((
ui_->dockWidget_graphView->isVisible() &&
ui_->graphViewer->isGridMapVisible()) ||
6289 (
ui_->dockWidget_occupancyGridView->isVisible() &&
ui_->checkBox_grid_2d->isChecked()))
6291 bool eroded = Parameters::defaultGridGlobalEroded();
6296 #ifdef RTABMAP_OCTOMAP 6297 if(
ui_->checkBox_octomap->isChecked())
6310 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
6312 grid.
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second);
6314 grid.
update(graphFiltered);
6315 map = grid.
getMap(xMin, yMin);
6318 ui_->label_timeGrid->setNum(
double(time.elapsed())/1000.0);
6323 if(
ui_->dockWidget_graphView->isVisible() &&
ui_->graphViewer->isGridMapVisible())
6325 ui_->graphViewer->updateMap(map8U, cellSize, xMin, yMin);
6327 if(
ui_->dockWidget_occupancyGridView->isVisible() &&
ui_->checkBox_grid_2d->isChecked())
6336 if(
ui_->dockWidget_occupancyGridView->isVisible())
6338 #ifdef RTABMAP_OCTOMAP 6339 if(
ui_->checkBox_octomap->isChecked())
6346 pcl::PointCloud<pcl::PointXYZ>::Ptr groundXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
6347 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
6348 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCellsXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
6349 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
6350 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
6351 pcl::PointCloud<pcl::PointXYZRGB>::Ptr emptyCellsRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
6353 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
6355 Transform pose = graphFiltered.at(iter->first);
6359 if(!iter->second.first.first.empty())
6361 if(iter->second.first.first.channels() == 4)
6370 if(!iter->second.first.second.empty())
6372 if(iter->second.first.second.channels() == 4)
6381 if(
ui_->checkBox_grid_empty->isChecked())
6383 if(!iter->second.second.empty())
6385 if(iter->second.second.channels() == 4)
6397 if(groundRGB->size())
6403 QColor(
ui_->lineEdit_groundColor->text()));
6406 if(groundXYZ->size())
6412 QColor(
ui_->lineEdit_groundColor->text()));
6415 if(obstaclesRGB->size())
6421 QColor(
ui_->lineEdit_obstacleColor->text()));
6424 if(obstaclesXYZ->size())
6430 QColor(
ui_->lineEdit_obstacleColor->text()));
6433 if(emptyCellsRGB->size())
6439 QColor(
ui_->lineEdit_emptyColor->text()));
6443 if(emptyCellsXYZ->size())
6449 QColor(
ui_->lineEdit_emptyColor->text()));
6457 ui_->graphViewer->fitInView(
ui_->graphViewer->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
6458 ui_->graphViewer->update();
6459 ui_->label_iterations->setNum(value);
6463 for(std::multimap<int, rtabmap::Link>::const_iterator iter=
graphLinks_.begin(); iter!=
graphLinks_.end(); ++iter)
6465 std::map<int, rtabmap::Transform>::const_iterator jterA = graph.find(iter->first);
6466 std::map<int, rtabmap::Transform>::const_iterator jterB = graph.find(iter->second.to());
6467 if(jterA != graph.end() && jterB != graph.end())
6474 Eigen::Vector3f vA, vB;
6477 vA[0] = x; vA[1] = y; vA[2] = z;
6479 vB[0] = x; vB[1] = y; vB[2] = z;
6480 length += (vB - vA).norm();
6484 ui_->label_pathLength->setNum(length);
6489 ui_->label_loopClosures->clear();
6490 ui_->label_poses->clear();
6491 ui_->label_rmse->clear();
6495 int fromId =
ui_->spinBox_optimizationsFrom->value();
6498 QMessageBox::warning(
this, tr(
""), tr(
"Graph optimization from id (%1) for which node is not linked to graph.\n Minimum=%2, Maximum=%3")
6508 std::map<int, rtabmap::Transform> poses =
odomPoses_;
6511 std::map<int, rtabmap::Transform> wmPoses;
6512 std::vector<int> & wmState =
wmStates_.at(fromId);
6513 for(
unsigned int i=0; i<wmState.size(); ++i)
6515 std::map<int, rtabmap::Transform>::iterator iter = poses.find(wmState[i]);
6516 if(iter!=poses.end())
6518 wmPoses.insert(*iter);
6521 if(!wmPoses.empty())
6527 UWARN(
"Empty WM poses!? Ignoring WM state... (root id=%d, wmState=%d)", fromId, wmState.size());
6534 int currentMapId =
mapIds_.at(fromId);
6535 for(std::map<int, rtabmap::Transform>::iterator iter=poses.begin(); iter!=poses.end();)
6539 poses.erase(iter++);
6548 ui_->menuExport_poses->setEnabled(
true);
6549 std::multimap<int, rtabmap::Link> links =
links_;
6555 int currentMapId =
mapIds_.at(fromId);
6556 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end();)
6558 if((iter->second.from()>0 && (!
uContains(
mapIds_, iter->second.from()) ||
mapIds_.at(iter->second.from()) != currentMapId)) ||
6559 (iter->second.to()>0 && (!
uContains(
mapIds_, iter->second.to()) ||
mapIds_.at(iter->second.to()) != currentMapId)))
6561 links.erase(iter++);
6571 if(
ui_->checkBox_ignorePoseCorrection->isChecked())
6573 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
6580 if(!poseFrom.
isNull() && !poseTo.isNull())
6583 iter->second =
Link(
6584 iter->second.from(),
6586 iter->second.type(),
6594 int totalNeighbor = 0;
6595 int totalNeighborMerged = 0;
6596 int totalGlobal = 0;
6597 int totalLocalTime = 0;
6598 int totalLocalSpace = 0;
6600 int totalPriors = 0;
6601 int totalLandmarks = 0;
6602 int totalGravity = 0;
6603 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end();)
6611 ++totalNeighborMerged;
6615 if(
ui_->checkBox_ignoreGlobalLoop->isChecked())
6617 links.erase(iter++);
6625 if(
ui_->checkBox_ignoreLocalLoopSpace->isChecked())
6627 links.erase(iter++);
6635 if(
ui_->checkBox_ignoreLocalLoopTime->isChecked())
6637 links.erase(iter++);
6645 if(
ui_->checkBox_ignoreUserLoop->isChecked())
6647 links.erase(iter++);
6655 if(
ui_->checkBox_ignoreLandmarks->isChecked())
6657 links.erase(iter++);
6660 UASSERT(iter->second.from() > 0 && iter->second.to() < 0);
6661 if(poses.find(iter->second.from()) != poses.end() && poses.find(iter->second.to()) == poses.end())
6663 poses.insert(std::make_pair(iter->second.to(), poses.at(iter->second.from())*iter->second.transform()));
6684 ui_->label_loopClosures->setText(tr(
"(%1, %2, %3, %4, %5, %6, %7, %8, %9)")
6686 .arg(totalNeighborMerged)
6688 .arg(totalLocalSpace)
6689 .arg(totalLocalTime)
6692 .arg(totalLandmarks)
6693 .arg(totalGravity));
6696 if(
ui_->checkBox_ignoreIntermediateNodes->isVisible() &&
6697 ui_->checkBox_ignoreIntermediateNodes->isChecked())
6699 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
6704 Link link = iter->second;
6707 std::multimap<int, Link>::iterator uter = links.find(link.
to());
6708 if(uter != links.end())
6711 poses.erase(link.
to());
6712 link = link.
merge(uter->second, uter->second.type());
6721 iter->second = link;
6730 std::map<int, rtabmap::Transform> posesOut;
6731 std::multimap<int, rtabmap::Link> linksOut;
6732 UINFO(
"Get connected graph from %d (%d poses, %d links)", fromId, (
int)poses.size(), (int)links.size());
6739 UINFO(
"Connected graph of %d poses and %d links", (
int)posesOut.size(), (int)linksOut.size());
6742 std::map<int, rtabmap::Transform> finalPoses = optimizer->
optimize(fromId, posesOut, linksOut,
ui_->checkBox_iterativeOptimization->isChecked()?&
graphes_:0);
6743 ui_->label_timeOptimization->setNum(
double(time.elapsed())/1000.0);
6745 if(posesOut.size() && finalPoses.empty())
6747 UWARN(
"Optimization failed... (poses=%d, links=%d).", (
int)posesOut.size(), (int)linksOut.size());
6750 QMessageBox::warning(
this, tr(
"Graph optimization error!"), tr(
"Graph optimization has failed. See the terminal for potential errors. " 6751 "Give it a try with %1=0 and %2=true.").arg(Parameters::kOptimizerStrategy().c_str()).arg(Parameters::kOptimizerVarianceIgnored().c_str()));
6755 QMessageBox::warning(
this, tr(
"Graph optimization error!"), tr(
"Graph optimization has failed. See the terminal for potential errors."));
6758 ui_->label_poses->setNum((
int)finalPoses.size());
6764 if(
ui_->doubleSpinBox_optimizationScale->value()!=-1.0)
6767 for(std::list<std::map<int, Transform> >::iterator iter=
graphes_.begin(); iter!=
graphes_.end(); ++iter)
6769 for(std::map<int, Transform>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
6771 jter->second = jter->second.clone();
6772 jter->second.x() *=
ui_->doubleSpinBox_optimizationScale->value();
6773 jter->second.y() *=
ui_->doubleSpinBox_optimizationScale->value();
6774 jter->second.z() *=
ui_->doubleSpinBox_optimizationScale->value();
6779 ui_->horizontalSlider_iterations->setMaximum((
int)
graphes_.size()-1);
6780 ui_->horizontalSlider_iterations->setValue((
int)
graphes_.size()-1);
6781 ui_->horizontalSlider_iterations->setEnabled(
true);
6782 ui_->spinBox_optimizationsFrom->setEnabled(
true);
6787 ui_->horizontalSlider_iterations->setEnabled(
false);
6788 ui_->spinBox_optimizationsFrom->setEnabled(
false);
6794 if(sender() ==
ui_->checkBox_grid_2d && !
ui_->checkBox_grid_2d->isChecked())
6802 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
6803 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
6804 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
6805 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
6806 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
6807 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
6816 #ifdef RTABMAP_OCTOMAP 6817 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
6818 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
6819 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
6820 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
6821 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
6822 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
6824 if(
ui_->checkBox_octomap->isChecked())
6831 if(
ui_->comboBox_octomap_rendering_type->currentIndex()>0)
6837 pcl::IndicesPtr obstacles(
new std::vector<int>);
6838 pcl::IndicesPtr empty(
new std::vector<int>);
6839 pcl::IndicesPtr ground(
new std::vector<int>);
6840 std::vector<double> prob;
6842 ui_->spinBox_grid_depth->value(),
6852 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
6853 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
6857 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
6858 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
6864 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZ>);
6865 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
6869 pcl::PointCloud<pcl::PointXYZ>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZ>);
6870 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
6875 if(
ui_->checkBox_grid_empty->isChecked())
6877 if(prob.size()==cloud->size())
6879 float occThr = Parameters::defaultGridGlobalOccupancyThr();
6880 Parameters::parse(
ui_->parameters_toolbox->getParameters(), Parameters::kGridGlobalOccupancyThr(), occThr);
6881 pcl::PointCloud<pcl::PointXYZRGB>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
6882 emptyCloud->resize(empty->size());
6883 for(
unsigned int i=0;i<empty->size(); ++i)
6885 emptyCloud->points.at(i).x = cloud->points.at(empty->at(i)).x;
6886 emptyCloud->points.at(i).y = cloud->points.at(empty->at(i)).y;
6887 emptyCloud->points.at(i).z = cloud->points.at(empty->at(i)).z;
6888 QColor hsv = QColor::fromHsv(
int(prob.at(empty->at(i))/occThr*240.0), 255, 255, 255);
6889 QRgb color = hsv.rgb();
6890 emptyCloud->points.at(i).r = qRed(color);
6891 emptyCloud->points.at(i).g = qGreen(color);
6892 emptyCloud->points.at(i).b = qBlue(color);
6900 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZ>);
6901 pcl::copyPointCloud(*cloud, *empty, *emptyCloud);
6910 if(
ui_->dockWidget_view3d->isVisible() &&
ui_->checkBox_showGrid->isChecked())
6924 link = findIter->second;
6931 link = findIter->second;
6936 if(findIter !=
links_.end())
6938 link = findIter->second;
6952 int from =
ids_.at(
ui_->horizontalSlider_A->value());
6953 int to =
ids_.at(
ui_->horizontalSlider_B->value());
6959 UDEBUG(
"%d -> %d", from, to);
6960 bool switchedIds =
false;
6963 UWARN(
"Cannot refine link to same node");
6971 UERROR(
"Not found link! (%d->%d)", from, to);
6975 UDEBUG(
"%d -> %d (type=%d)", currentLink.
from(), currentLink.
to(), currentLink.
type());
6977 if(
ui_->checkBox_showOptimized->isChecked() &&
6980 (int)
graphes_.size()-1 ==
ui_->horizontalSlider_iterations->maximum())
6982 std::map<int, rtabmap::Transform> & graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
6985 std::map<int, rtabmap::Transform>::iterator iterFrom = graph.find(currentLink.
from());
6986 std::map<int, rtabmap::Transform>::iterator iterTo = graph.find(currentLink.
to());
6987 if(iterFrom != graph.end() && iterTo != graph.end())
6994 else if(
ui_->checkBox_ignorePoseCorrection->isChecked() &&
7002 if(!poseFrom.
isNull() && !poseTo.isNull())
7004 t = poseFrom.
inverse() * poseTo;
7017 UERROR(
"Signature %d not found!", currentLink.
from());
7027 std::map<int, rtabmap::Transform> scanPoses;
7031 userData.type() == CV_8SC1 &&
7032 userData.rows == 1 &&
7033 userData.cols >= 8 &&
7034 userData.at<
char>(userData.cols-1) == 0 &&
7035 memcmp(userData.data,
"SCANS:", 6) == 0 &&
7036 currentLink.
from() > currentLink.
to())
7038 std::string scansStr = (
const char *)userData.data;
7039 UINFO(
"Detected \"%s\" in links's user data", scansStr.c_str());
7040 if(!scansStr.empty())
7042 std::list<std::string> strs =
uSplit(scansStr,
':');
7043 if(strs.size() == 2)
7045 std::list<std::string> strIds =
uSplit(strs.rbegin()->c_str(),
';');
7046 for(std::list<std::string>::iterator iter=strIds.begin(); iter!=strIds.end(); ++iter)
7048 int id = atoi(iter->c_str());
7055 UERROR(
"Not found %d node!",
id);
7061 if(scanPoses.size()>1)
7067 std::map<int, rtabmap::Transform> posesOut;
7068 std::multimap<int, rtabmap::Link> linksOut;
7076 if(scanPoses.size() != posesOut.size())
7078 UWARN(
"Scan poses input and output are different! %d vs %d", (
int)scanPoses.size(), (int)posesOut.size());
7079 UWARN(
"Input poses: ");
7080 for(std::map<int, Transform>::iterator iter=scanPoses.begin(); iter!=scanPoses.end(); ++iter)
7082 UWARN(
" %d", iter->first);
7084 UWARN(
"Input links: ");
7086 for(std::multimap<int, Link>::iterator iter=modifiedLinks.begin(); iter!=modifiedLinks.end(); ++iter)
7088 UWARN(
" %d->%d", iter->second.from(), iter->second.to());
7092 scanPoses = optimizer->
optimize(currentLink.
to(), posesOut, linksOut);
7095 std::map<int, Transform> filteredScanPoses = scanPoses;
7096 float proximityFilteringRadius = 0.0f;
7097 Parameters::parse(parameters, Parameters::kRGBDProximityPathFilteringRadius(), proximityFilteringRadius);
7098 if(scanPoses.size() > 2 && proximityFilteringRadius > 0.0f)
7103 filteredScanPoses.insert(*scanPoses.find(currentLink.
to()));
7110 int maxPoints = fromScan.
size();
7113 UWARN(
"From scan %d is empty!", fromS->
id());
7115 pcl::PointCloud<pcl::PointXYZ>::Ptr assembledToClouds(
new pcl::PointCloud<pcl::PointXYZ>);
7116 pcl::PointCloud<pcl::PointNormal>::Ptr assembledToNormalClouds(
new pcl::PointCloud<pcl::PointNormal>);
7117 pcl::PointCloud<pcl::PointXYZI>::Ptr assembledToIClouds(
new pcl::PointCloud<pcl::PointXYZI>);
7118 pcl::PointCloud<pcl::PointXYZINormal>::Ptr assembledToNormalIClouds(
new pcl::PointCloud<pcl::PointXYZINormal>);
7119 pcl::PointCloud<pcl::PointXYZRGB>::Ptr assembledToRGBClouds(
new pcl::PointCloud<pcl::PointXYZRGB>);
7120 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr assembledToNormalRGBClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
7121 for(std::map<int, Transform>::const_iterator iter = filteredScanPoses.begin(); iter!=filteredScanPoses.end(); ++iter)
7123 if(iter->first != currentLink.
from())
7173 if(scan.
size() > maxPoints)
7175 maxPoints = scan.
size();
7180 UWARN(
"scan format of %d is not the same than from scan %d: %d vs %d", data.
id(), fromS->
id(), scan.
format(), fromScan.
format());
7185 UWARN(
"Laser scan not found for signature %d", iter->first);
7190 cv::Mat assembledScan;
7191 if(assembledToNormalClouds->size())
7195 else if(assembledToClouds->size())
7199 else if(assembledToNormalIClouds->size())
7203 else if(assembledToIClouds->size())
7207 else if(assembledToNormalRGBClouds->size())
7212 else if(assembledToRGBClouds->size())
7219 UWARN(
"Assembled scan is empty!");
7244 UERROR(
"Signature %d not found!", currentLink.
to());
7249 bool reextractVisualFeatures =
uStr2Bool(parameters.at(Parameters::kRGBDLoopClosureReextractFeatures()));
7251 if( reg->isScanRequired() ||
7252 reg->isUserDataRequired() ||
7253 reextractVisualFeatures ||
7256 dbDriver_->
loadNodeData(fromS, reextractVisualFeatures || !silent, reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
7257 dbDriver_->
loadNodeData(toS, reextractVisualFeatures || !silent, reg->isScanRequired() || !silent, reg->isUserDataRequired() || !silent, !silent);
7266 if(reextractVisualFeatures)
7269 fromS->
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
7274 if(reg->isScanRequired())
7276 if(
ui_->checkBox_icp_from_depth->isChecked())
7279 cv::Mat tmpA, tmpB, tmpC, tmpD;
7284 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
7285 ui_->doubleSpinBox_icp_maxDepth->value(),
7286 ui_->doubleSpinBox_icp_minDepth->value(),
7288 ui_->parameters_toolbox->getParameters());
7291 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
7292 ui_->doubleSpinBox_icp_maxDepth->value(),
7293 ui_->doubleSpinBox_icp_minDepth->value(),
7295 ui_->parameters_toolbox->getParameters());
7296 int maxLaserScans = cloudFrom->size();
7302 UWARN(
"There are laser scans in data, but generate laser scan from " 7303 "depth image option is activated. Ignoring saved laser scans...");
7314 if(reg->isImageRequired() && reextractVisualFeatures)
7316 cv::Mat tmpA, tmpB, tmpC, tmpD;
7321 UINFO(
"Uncompress time: %f s", timer.
ticks());
7323 if(fromS->
id() < toS->
id())
7325 transform = reg->computeTransformationMod(*fromS, *toS, t, &info);
7329 transform = reg->computeTransformationMod(*toS, *fromS, t.isNull()?t:t.inverse(), &info);
7335 UINFO(
"(%d ->%d) Registration time: %f s", currentLink.
from(), currentLink.
to(), timer.
ticks());
7343 info.
covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001;
7348 transform = transform.
inverse();
7353 bool updated =
false;
7354 std::multimap<int, Link>::iterator iter =
linksRefined_.find(currentLink.
from());
7357 if(iter->second.to() == currentLink.
to() &&
7358 iter->second.type() == currentLink.
type())
7360 iter->second = newLink;
7368 linksRefined_.insert(std::make_pair(newLink.from(), newLink));
7372 if(updated && !silent)
7377 if(!silent &&
ui_->dockWidget_constraints->isVisible())
7379 if(toS && fromS->
id() > 0 && toS->
id() > 0)
7382 std::multimap<int, cv::KeyPoint> keypointsFrom;
7383 std::multimap<int, cv::KeyPoint> keypointsTo;
7386 for(std::map<int, int>::const_iterator iter=fromS->
getWords().begin(); iter!=fromS->
getWords().end(); ++iter)
7388 keypointsFrom.insert(keypointsFrom.end(), std::make_pair(iter->first, fromS->
getWordsKpts()[iter->second]));
7393 for(std::map<int, int>::const_iterator iter=toS->
getWords().begin(); iter!=toS->
getWords().end(); ++iter)
7395 keypointsTo.insert(keypointsTo.end(), std::make_pair(iter->first, toS->
getWordsKpts()[iter->second]));
7421 if(toS && fromS->
id() > 0 && toS->
id() > 0)
7424 std::multimap<int, cv::KeyPoint> keypointsFrom;
7425 std::multimap<int, cv::KeyPoint> keypointsTo;
7428 for(std::map<int, int>::const_iterator iter=fromS->
getWords().begin(); iter!=fromS->
getWords().end(); ++iter)
7430 keypointsFrom.insert(keypointsFrom.end(), std::make_pair(iter->first, fromS->
getWordsKpts()[iter->second]));
7435 for(std::map<int, int>::const_iterator iter=toS->
getWords().begin(); iter!=toS->
getWords().end(); ++iter)
7437 keypointsTo.insert(keypointsTo.end(), std::make_pair(iter->first, toS->
getWordsKpts()[iter->second]));
7453 QMessageBox::warning(
this,
7455 tr(
"Cannot find a transformation between nodes %1 and %2: %3").arg(currentLink.
from()).arg(currentLink.
to()).arg(info.
rejectedMsg.c_str()));
7463 int from =
ids_.at(
ui_->horizontalSlider_A->value());
7464 int to =
ids_.at(
ui_->horizontalSlider_B->value());
7470 bool switchedIds =
false;
7473 UWARN(
"Cannot add link to same node");
7483 std::list<Signature*> signatures;
7498 bool loopCovLimited = Parameters::defaultRGBDLoopCovLimited();
7499 Parameters::parse(parameters, Parameters::kRGBDLoopCovLimited(), loopCovLimited);
7509 ids.push_back(from);
7512 if(signatures.size() != 2)
7514 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
7520 fromS = *signatures.begin();
7521 toS = *signatures.rbegin();
7523 bool reextractVisualFeatures =
uStr2Bool(parameters.at(Parameters::kRGBDLoopClosureReextractFeatures()));
7526 reextractVisualFeatures ||
7534 if(reextractVisualFeatures)
7537 fromS->
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
7542 else if(!reextractVisualFeatures && fromS->
getWords().empty() && toS->
getWords().empty())
7544 UWARN(
"\"%s\" is false and signatures (%d and %d) don't have words, " 7545 "registration will not be possible. Set \"%s\" to true.",
7546 Parameters::kRGBDLoopClosureReextractFeatures().c_str(),
7549 Parameters::kRGBDLoopClosureReextractFeatures().c_str());
7553 bool guessFromGraphRejected =
false;
7559 std::map<int, Transform> optimizedPoses =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
7560 if(optimizedPoses.size() > 0)
7562 std::map<int, Transform>::iterator fromIter = optimizedPoses.find(from);
7563 std::map<int, Transform>::iterator toIter = optimizedPoses.find(to);
7564 if(fromIter != optimizedPoses.end() &&
7565 toIter != optimizedPoses.end())
7569 if(QMessageBox::question(
this,
7570 tr(
"Add constraint from optimized graph"),
7571 tr(
"Registration is done without vision (see %1 parameter), " 7572 "do you want to use a guess from the optimized graph?" 7574 "\n\nOtherwise, if " 7575 "the database has images, it is recommended to use %2=2 instead so that " 7576 "the guess can be found visually.")
7577 .arg(Parameters::kRegStrategy().c_str()).arg(Parameters::kRegStrategy().c_str()),
7578 QMessageBox::Yes | QMessageBox::No,
7579 QMessageBox::Yes) == QMessageBox::Yes)
7581 guess = fromIter->second.inverse() * toIter->second;
7585 guessFromGraphRejected =
true;
7590 guess = fromIter->second.inverse() * toIter->second;
7595 if(guess.isNull() && !silent && !guessFromGraphRejected)
7597 if(QMessageBox::question(
this,
7598 tr(
"Add constraint without guess"),
7599 tr(
"Registration is done without vision (see %1 parameter) and we cannot (or we don't want to) find relative " 7600 "transformation between the nodes with the current graph. Do you want to use an identity " 7601 "transform for ICP guess? " 7603 "\n\nOtherwise, if the database has images, it is recommended to use %2=2 " 7604 "instead so that the guess can be found visually.")
7605 .arg(Parameters::kRegStrategy().c_str()).arg(Parameters::kRegStrategy().c_str()),
7606 QMessageBox::Yes | QMessageBox::Abort,
7607 QMessageBox::Abort) == QMessageBox::Yes)
7609 guess.setIdentity();
7613 guessFromGraphRejected =
true;
7625 if(odomMaxInf.size() == 6 && information.cols==6 && information.rows==6)
7627 for(
int i=0; i<6; ++i)
7629 if(information.at<
double>(i,i) > odomMaxInf[i])
7631 information.at<
double>(i,i) = odomMaxInf[i];
7638 else if(!silent && !guessFromGraphRejected)
7640 QMessageBox::StandardButton button = QMessageBox::warning(
this,
7642 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()),
7643 QMessageBox::Yes | QMessageBox::No,
7645 if(button == QMessageBox::Yes)
7657 bool updateConstraints = newLink.
isValid();
7658 float maxOptimizationError =
uStr2Float(
ui_->parameters_toolbox->getParameters().at(Parameters::kRGBDOptimizeMaxError()));
7660 maxOptimizationError > 0.0f &&
7661 uStr2Int(
ui_->parameters_toolbox->getParameters().at(Parameters::kOptimizerIterations())) > 0.0
f)
7663 int fromId = newLink.
from();
7665 linksIn.insert(std::make_pair(newLink.
from(), newLink));
7666 const Link * maxLinearLink = 0;
7667 const Link * maxAngularLink = 0;
7668 float maxLinearErrorRatio = 0.0f;
7669 float maxAngularErrorRatio = 0.0f;
7671 std::map<int, Transform> poses;
7672 std::multimap<int, Link> links;
7680 const std::map<int, Transform> & optimizedPoses =
graphes_.back();
7681 for(std::map<int, Transform>::iterator iter = poses.begin(); iter!=poses.end(); ++iter)
7683 if(optimizedPoses.find(iter->first) != optimizedPoses.end())
7685 iter->second = optimizedPoses.at(iter->first);
7689 UASSERT(poses.find(fromId) != poses.end());
7690 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());
7691 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());
7693 std::map<int, Transform> posesIn = poses;
7694 poses = optimizer->
optimize(fromId, posesIn, links);
7695 if(posesIn.size() && poses.empty())
7697 UWARN(
"Optimization failed... (poses=%d, links=%d).", (
int)posesIn.size(), (int)links.size());
7702 float maxLinearError = 0.0f;
7703 float maxAngularError = 0.0f;
7707 maxLinearErrorRatio,
7708 maxAngularErrorRatio,
7715 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()));
7716 if(maxLinearErrorRatio > maxOptimizationError)
7718 msg =
uFormat(
"Rejecting edge %d->%d because " 7719 "graph error is too large (abs=%f m) after optimization (ratio %f for edge %d->%d, stddev=%f m). " 7724 maxLinearErrorRatio,
7725 maxLinearLink->
from(),
7726 maxLinearLink->
to(),
7728 Parameters::kRGBDOptimizeMaxError().c_str(),
7729 maxOptimizationError);
7734 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()));
7735 if(maxAngularErrorRatio > maxOptimizationError)
7737 msg =
uFormat(
"Rejecting edge %d->%d because " 7738 "graph error is too large (abs=%f deg) after optimization (ratio %f for edge %d->%d, stddev=%f deg). " 7742 maxAngularError*180.0f/CV_PI,
7743 maxAngularErrorRatio,
7744 maxAngularLink->
from(),
7745 maxAngularLink->
to(),
7747 Parameters::kRGBDOptimizeMaxError().c_str(),
7748 maxOptimizationError);
7754 msg =
uFormat(
"Rejecting edge %d->%d because graph optimization has failed!",
7760 UWARN(
"%s", msg.c_str());
7763 QMessageBox::warning(
this,
7765 tr(
"%1").arg(msg.c_str()));
7768 updateConstraints =
false;
7772 if(updateConstraints)
7781 if(newLink.
from() < newLink.
to())
7793 if((updateConstraints && newLink.
from() > newLink.
to()) || (!updateConstraints && switchedIds))
7800 if(updateConstraints)
7807 std::multimap<int, cv::KeyPoint> keypointsFrom;
7808 std::multimap<int, cv::KeyPoint> keypointsTo;
7811 for(std::map<int, int>::const_iterator iter=fromS->
getWords().begin(); iter!=fromS->
getWords().end(); ++iter)
7813 keypointsFrom.insert(keypointsFrom.end(), std::make_pair(iter->first, fromS->
getWordsKpts()[iter->second]));
7818 for(std::map<int, int>::const_iterator iter=toS->
getWords().begin(); iter!=toS->
getWords().end(); ++iter)
7820 keypointsTo.insert(keypointsTo.end(), std::make_pair(iter->first, toS->
getWordsKpts()[iter->second]));
7827 else if(updateConstraints)
7834 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
7839 return updateConstraints;
7844 int from =
ids_.at(
ui_->horizontalSlider_A->value());
7845 int to =
ids_.at(
ui_->horizontalSlider_B->value());
7855 UWARN(
"Cannot reset link to same node");
7872 int from =
ids_.at(
ui_->horizontalSlider_A->value());
7873 int to =
ids_.at(
ui_->horizontalSlider_B->value());
7876 int position =
ui_->horizontalSlider_loops->value();
7891 UWARN(
"Cannot reject link to same node");
7895 bool removed =
false;
7898 std::multimap<int, Link>::iterator iter;
7904 QMessageBox::StandardButton button = QMessageBox::warning(
this, tr(
"Reject link"),
7905 tr(
"Removing the neighbor link %1->%2 will split the graph. Do you want to continue?").arg(from).arg(to),
7906 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
7907 if(button != QMessageBox::Yes)
7937 const std::multimap<int, rtabmap::Link> & edgeConstraints)
7941 std::multimap<int, rtabmap::Link> links;
7942 for(std::multimap<int, rtabmap::Link>::const_iterator iter=edgeConstraints.begin();
7943 iter!=edgeConstraints.end();
7946 std::multimap<int, rtabmap::Link>::iterator findIter;
7951 UDEBUG(
"Removed link (%d->%d, %d)", iter->second.from(), iter->second.to(), iter->second.type());
7958 links.insert(*findIter);
7959 UDEBUG(
"Updated link (%d->%d, %d)", iter->second.from(), iter->second.to(), iter->second.type());
7963 links.insert(*iter);
7967 for(std::multimap<int, rtabmap::Link>::const_iterator iter=
linksAdded_.begin();
7974 links.insert(*findIter);
7975 UDEBUG(
"Added refined link (%d->%d, %d)", findIter->second.from(), findIter->second.to(), findIter->second.type());
7979 UDEBUG(
"Added link (%d->%d, %d)", iter->second.from(), iter->second.to(), iter->second.type());
7980 links.insert(*iter);
7988 UDEBUG(
"%d %d", from, to);
7991 int position =
ui_->horizontalSlider_loops->value();
7992 std::multimap<int, Link> linksSortedByParents;
7993 for(std::multimap<int, rtabmap::Link>::iterator iter = links.begin(); iter!=links.end(); ++iter)
7995 if(iter->second.to() > iter->second.from())
7997 linksSortedByParents.insert(std::make_pair(iter->second.to(), iter->second.inverse()));
7999 else if(iter->second.to() != iter->second.from())
8001 linksSortedByParents.insert(*iter);
8004 for(std::multimap<int, rtabmap::Link>::iterator iter = linksSortedByParents.begin(); iter!=linksSortedByParents.end(); ++iter)
8006 if(!iter->second.transform().isNull())
8011 if((iter->second.from() == from && iter->second.to() == to) ||
8012 (iter->second.to() == from && iter->second.from() == to))
8021 UERROR(
"Transform null for link from %d to %d", iter->first, iter->second.to());
8032 ui_->horizontalSlider_loops->setMinimum(0);
8033 ui_->horizontalSlider_loops->setMaximum(
loopLinks_.size()-1);
8034 ui_->horizontalSlider_loops->setEnabled(
true);
8035 if(position !=
ui_->horizontalSlider_loops->value())
8037 ui_->horizontalSlider_loops->setValue(position);
8046 ui_->horizontalSlider_loops->setEnabled(
false);
8057 for(QStringList::const_iterator iter=parametersChanged.constBegin();
8058 iter!=parametersChanged.constEnd() && (!updateStereo || !
updateGraphView);
8061 QString group = iter->split(
'/').first();
8062 if(!updateStereo && group ==
"Stereo")
8064 updateStereo =
true;
8067 if(!updateGraphView && group ==
"Optimize")
8069 updateGraphView =
true;
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 isUserDataRequired() const
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_
int sessionExported() const
std::map< int, std::pair< float, cv::Point3f > > generatedLocalMapsInfo_
cv::Mat getModifiedMap() const
bool update(const std::map< int, Transform > &poses)
void incrementStep(int steps=1)
Transform RTABMAP_EXP transformFromXYZCorrespondencesSVD(const pcl::PointCloud< pcl::PointXYZ > &cloud1, const pcl::PointCloud< pcl::PointXYZ > &cloud2)
QString getIniFilePath() const
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
int getMaxTextures() const
void sliderBValueChanged(int)
long getFeaturesMemoryUsed() const
long getGridsMemoryUsed() const
T uMean(const T *v, unsigned int size)
long getImagesMemoryUsed() const
cv::Point3f RTABMAP_EXP projectDisparityTo3D(const cv::Point2f &pt, float disparity, const StereoCameraModel &model)
double getAngularVariance() const
std::map< int, Transform > RTABMAP_EXP radiusPosesFiltering(const std::map< int, Transform > &poses, float radius, float angle, bool keepLatest=true)
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
const cv::Mat & data() const
void setCancelButtonVisible(bool visible)
void saveOptimizedPoses(const std::map< int, Transform > &optimizedPoses, const Transform &lastlocalizationPose) const
Signature * loadSignature(int id, bool *loadedFromTrash=0)
std::vector< K > uKeys(const std::multimap< K, V > &mm)
int getBlendingDecimation() const
long getUserDataMemoryUsed() const
const LaserScan & laserScanCompressed() const
const cv::Mat & R() const
double UTILITE_EXP uStr2Double(const std::string &str)
void updateCameraFrustum(const Transform &pose, const StereoCameraModel &model)
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)
bool isGainCompensation() const
virtual void resizeEvent(QResizeEvent *anEvent)
bool isDepthExported() const
void addOrUpdateCoordinate(const std::string &id, const Transform &transform, double scale, bool foreground=false)
std::map< int, rtabmap::Transform > gpsPoses_
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
Transform computeTransformationMod(Signature &from, Signature &to, Transform guess=Transform::getIdentity(), RegistrationInfo *info=0) const
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)
double getLinearVariance() const
void getAllNodeIds(std::set< int > &ids, bool ignoreChildren=false, bool ignoreBadSignatures=false) const
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)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP removeNaNFromPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud)
pcl::PCLPointCloud2::Ptr RTABMAP_EXP laserScanToPointCloud2(const LaserScan &laserScan, const Transform &transform=Transform())
long getWordsMemoryUsed() const
void setMap(const cv::Mat &map)
void updateConstraintView()
void setColorMap(uCvQtDepthColorMap type)
float UTILITE_EXP uStr2Float(const std::string &str)
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)
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)
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 *labelVelocity, QLabel *labelCalib, QLabel *labelScan, QLabel *labelGravity, QLabel *labelGps, QLabel *labelSensors, bool updateConstraintView)
void getNodeData(int signatureId, SensorData &data, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const
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 & F() const
std::map< std::string, std::string > ParametersMap
void loadWords(const std::set< int > &wordIds, std::list< VisualWord * > &vws)
float gridCellSize() const
static void writeINI(const std::string &configFile, const ParametersMap ¶meters)
bool isCovarianceIgnored() const
void setCellSize(float cellSize)
void setGPS(const GPS &gps)
std::vector< int > inliersIDs
Some conversion functions.
const cv::Mat & gridGroundCellsRaw() const
void addValue(UPlotItem *data)
const std::string & getUrl() const
void setImage(const QImage &image)
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_
const LaserScan & laserScanRaw() const
void loadLinks(int signatureId, std::multimap< int, Link > &links, Link::Type type=Link::kUndef) const
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_
const cv::Mat & imageRaw() const
void generateGraph(const std::string &fileName, const std::set< int > &ids=std::set< int >(), const std::map< int, Signature * > &otherSignatures=std::map< int, Signature * >())
void notifyParametersChanged(const QStringList &)
ExportCloudsDialog * exportDialog_
static void setLevel(ULogger::Level level)
bool containsLink(std::multimap< int, Link > &links, int from, int to)
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)
void refineAllLoopClosureLinks()
std::vector< cv::KeyPoint > generateKeypoints(const cv::Mat &image, const cv::Mat &mask=cv::Mat())
const Transform & transform() const
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP laserScanToPointCloud(const LaserScan &laserScan, const Transform &transform=Transform())
double rotVariance(bool minimum=true) const
const double & altitude() const
const double & longitude() const
QMap< int, int > idToIndex_
const std::vector< cv::KeyPoint > & getWordsKpts() const
T uMin(const T *v, unsigned int size, unsigned int &index)
void setDBDriver(const DBDriver *dbDriver)
std::map< int, LaserScan > modifiedLaserScans_
bool addCloudTextureMesh(const std::string &id, const pcl::TextureMesh::Ptr &textureMesh, const cv::Mat &texture, const Transform &pose=Transform::getIdentity())
QDialog * editDepthDialog_
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
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_
void detectMoreLoopClosures()
std::map< int, std::vector< int > > getAllStatisticsWmStates() const
EditDepthArea * editDepthArea_
cv::Mat RTABMAP_EXP laserScan2dFromPointCloud(const pcl::PointCloud< pcl::PointXYZ > &cloud, const Transform &transform=Transform(), bool filterNaNs=true)
std::multimap< int, rtabmap::Link > linksRefined_
bool openConnection(const std::string &url, bool overwritten=false)
void loadSettings(QSettings &settings, const QString &group="")
#define UASSERT(condition)
double targetFramerate() const
bool isDepth2dExported() const
bool update(const std::map< int, Transform > &poses)
cv::Mat getModifiedImage() const
void setupMainLayout(bool vertical)
void getLastNodeIds(std::set< int > &ids) 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)
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)
bool getLaserScanInfo(int signatureId, LaserScan &info) const
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
bool isValidForProjection() const
void setSceneRect(const QRectF &rect)
const CameraModel & left() const
std::list< std::list< int > > RTABMAP_EXP clusterPolygons(const std::vector< std::set< int > > &neighborPolygons, int minClusterSize=0)
Transform getTransform() const
virtual ~DatabaseViewer()
const std::multimap< int, int > & getWords() const
static Feature2D * create(const ParametersMap ¶meters=ParametersMap())
std::map< int, int > mapIds_
#define ULOGGER_DEBUG(...)
void updateWordsMatching(const std::vector< int > &inliers=std::vector< int >())
std::map< int, GPS > gpsValues_
void getAllLinks(std::multimap< int, Link > &links, bool ignoreNullLinks=true, bool withLandmarks=false) const
QImage uCvMat2QImage(const cv::Mat &image, bool isBgr=true, uCvQtDepthColorMap colorMap=uCvQtDepthWhiteToBlack)
int framesIgnored() 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()
long getLaserScansMemoryUsed() const
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 loadNodeData(Signature *signature, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const
void loadSignatures(const std::list< int > &ids, std::list< Signature * > &signatures, std::set< int > *loadedFromTrash=0)
void setImageDepth(const cv::Mat &imageDepth)
const double & error() const
int getTextureBrightnessConstrastRatioHigh() const
const cv::Mat & T() 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)
std::map< int, std::pair< std::map< std::string, float >, double > > getAllStatistics() const
const cv::Mat & E() const
QString outputPath() const
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< double > RTABMAP_EXP getMaxOdomInf(const std::multimap< int, Link > &links)
Link merge(const Link &link, Type outputType) const
bool isScanRequired() const
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_
cv::Mat load2DMap(float &xMin, float &yMin, float &cellSize) const
std::map< int, std::vector< int > > wmStates_
void removeOccupancyGridMap()
void regenerateLocalMaps()
void setCloudPointSize(const std::string &id, int size)
bool getCalibration(int signatureId, std::vector< CameraModel > &models, StereoCameraModel &stereoModel) const
int getLastDictionarySize() const
bool isExposeFusion() const
void sliderIterationsValueChanged(int)
void setMaximumSteps(int steps)
const cv::Mat & userDataCompressed() 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)
long getStatisticsMemoryUsed() const
Transform localTransform() const
const double & latitude() const
long getCalibrationsMemoryUsed() const
const cv::Mat & infMatrix() const
std::map< int, int > weights_
std::multimap< int, rtabmap::Link > linksRemoved_
float angleIncrement() const
void updateDepthImage(int nodeId, const cv::Mat &image)
const cv::Mat & depthOrRightRaw() const
long getDepthImagesMemoryUsed() const
double getGainBeta() const
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 exportPoses(int format)
void setProgressDialogToMax()
GeodeticCoords toGeodeticCoords() const
void setEnvSensors(const EnvSensors &sensors)
std::map< int, rtabmap::Transform > odomPoses_
bool uContains(const std::list< V > &list, const V &value)
bool isUserDataExported() 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)
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
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_
static Stereo * create(const ParametersMap ¶meters=ParametersMap())
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
CloudViewer * stereoViewer_
bool isFrustumShown() const
bool isRgbExported() const
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)
double transVariance(bool minimum=true) const
static std::string getType(const std::string ¶mKey)
void restoreDefaultSettings()
const cv::Mat & gridEmptyCellsRaw() const
T uMax(const T *v, unsigned int size, unsigned int &index)
void uSleep(unsigned int ms)
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) const
std::vector< std::vector< RTABMAP_PCL_INDEX > > RTABMAP_EXP convertPolygonsFromPCL(const std::vector< pcl::Vertices > &polygons)
void refineAllLinks(const QList< Link > &links)
cv::Mat uncompressUserDataConst() const
rtabmap::DBDriver * dbDriver_
cv::Mat RTABMAP_EXP convertMap2Image8U(const cv::Mat &map8S, bool pgmFormat=false)
static const ParametersMap & getDefaultParameters()
void RTABMAP_EXP fixTextureMeshForVisualization(pcl::TextureMesh &textureMesh)
const double & longitude() const
const std::vector< CameraModel > & cameraModels() const
const Transform & getPose() 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
void addOrUpdateGraph(const std::string &id, const pcl::PointCloud< pcl::PointXYZ >::Ptr &graph, const QColor &color=Qt::gray)
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 >())
const double & altitude() const
virtual Type type() const =0
static Registration * create(const ParametersMap ¶meters)
bool isOdomExported() const
cv::Point3d toENU_WGS84(const GeodeticCoords &origin) const
const std::vector< cv::Point3f > & getWords3() const
SensorData & sensorData()
void updateCameraFrustums(const Transform &pose, const std::vector< CameraModel > &models)
const CameraModel & right() const
std::multimap< int, Link >::iterator RTABMAP_EXP findLink(std::multimap< int, Link > &links, int from, int to, bool checkBothWays=true)
void showCloseButton(bool visible=true)
bool RTABMAP_EXP databaseRecovery(const std::string &corruptedDatabase, bool keepCorruptedDatabase=true, std::string *errorMsg=0, ProgressState *progressState=0)
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)
cv::Mat RTABMAP_EXP fillDepthHoles(const cv::Mat &depth, int maximumHoleSize=1, float errorRatio=0.02f)
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)
ParametersMap getLastParameters() const
void updateAllLoopClosureCovariances()
ULogger class and convenient macros.
const StereoCameraModel & stereoCameraModel() const
std::set< int > lastWmIds_
void feed(const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &cloudA, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &cloudB, const Transform &transformB)
bool isImageRequired() const
int getTotalDictionarySize() const
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
std::string getDatabaseVersion() const
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 removeCoordinate(const std::string &id)
bool init(const QString &path, bool recordInRAM=true)
std::map< int, std::pair< std::pair< cv::Mat, cv::Mat >, cv::Mat > > localMaps_
void setGroundTruth(const Transform &pose)
cv::Mat RTABMAP_EXP cvtDepthFromFloat(const cv::Mat &depth32F)
CloudViewer * cloudViewer_
void updateAllNeighborCovariances()
void forceAssembling(bool enabled)
int getTextureSize() const
std::map< EnvSensor::Type, EnvSensor > EnvSensors
cv::Mat createProjectionMap(float &xMin, float &yMin, float &gridCellSize, float minGridSize=0.0f, unsigned int treeDepth=0)
void saveSettings(QSettings &settings, const QString &group="") const
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)
DatabaseViewer(const QString &ini=QString(), QWidget *parent=0)
GLM_FUNC_DECL genType::value_type length(genType const &x)
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)
const double & latitude() const
int getTextureBrightnessConstrastRatioLow() const
const Transform & localTransform() const
void save2DMap(const cv::Mat &map, float xMin, float yMin, float cellSize) const
const double & bearing() const
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,...)
std::string UTILITE_EXP uNumber2Str(unsigned int number)
cv::Mat getMap(float &xMin, float &yMin) const
void regenerateSavedMap()
static LaserScan backwardCompatibility(const cv::Mat &oldScanFormat, int maxPoints=0, int maxRange=0, const Transform &localTransform=Transform::getIdentity())
long getLinksMemoryUsed() const
CloudViewer * occupancyGridViewer_
void exportPosesRGBDSLAM()
std::map< int, std::pair< std::pair< cv::Mat, cv::Mat >, cv::Mat > > generatedLocalMaps_
void getLastWordId(int &id) const
void removeAllFrustums(bool exceptCameraReference=false)
void fromENU_WGS84(const cv::Point3d &enu, const GeodeticCoords &origin)
static Optimizer * create(const ParametersMap ¶meters)
void setFeatures(const std::multimap< int, cv::KeyPoint > &refWords, const cv::Mat &depth=cv::Mat(), const QColor &color=Qt::yellow)
const cv::Point3f & gridViewPoint() const
int getLastNodesSize() const
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)
long getNodesMemoryUsed() 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)
bool hasIntensity() const
const cv::Mat & gridObstacleCellsRaw() const
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 Transform & localTransform() const
void sliderAValueChanged(int)
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)
std::map< int, Transform > loadOptimizedPoses(Transform *lastlocalizationPose=0) const
LaserScan RTABMAP_EXP laserScanFromPointCloud(const pcl::PCLPointCloud2 &cloud, bool filterNaNs=true, bool is2D=false, const Transform &transform=Transform())
const double & stamp() const