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> 46 #include <opencv2/core/core_c.h> 47 #include <opencv2/imgproc/types_c.h> 48 #include <opencv2/highgui/highgui.hpp> 84 #include <pcl/io/pcd_io.h> 85 #include <pcl/io/ply_io.h> 86 #include <pcl/io/obj_io.h> 87 #include <pcl/filters/voxel_grid.h> 88 #include <pcl/common/transforms.h> 89 #include <pcl/common/common.h> 91 #ifdef RTABMAP_OCTOMAP 102 editDepthDialog_(new QDialog(this)),
103 savedMaximized_(
false),
106 useLastOptimizedGraphAsGuess_(
false)
115 ui_ =
new Ui_DatabaseViewer();
117 ui_->buttonBox->setVisible(
false);
118 connect(
ui_->buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(close()));
120 ui_->comboBox_logger_level->setVisible(parent==0);
121 ui_->label_logger_level->setVisible(parent==0);
122 connect(
ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
updateLoggerLevel()));
123 connect(
ui_->actionVertical_Layout, SIGNAL(toggled(
bool)),
this, SLOT(
setupMainLayout(
bool)));
128 vLayout->setContentsMargins(0,0,0,0);
129 vLayout->setSpacing(0);
131 QDialogButtonBox * buttonBox =
new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel | QDialogButtonBox::Reset, Qt::Horizontal,
editDepthDialog_);
132 vLayout->addWidget(buttonBox);
135 connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()),
editDepthArea_, SLOT(resetChanges()));
139 QString title(
"RTAB-Map Database Viewer[*]");
140 this->setWindowTitle(title);
142 ui_->dockWidget_constraints->setVisible(
false);
143 ui_->dockWidget_graphView->setVisible(
false);
144 ui_->dockWidget_occupancyGridView->setVisible(
false);
145 ui_->dockWidget_guiparameters->setVisible(
false);
146 ui_->dockWidget_coreparameters->setVisible(
false);
147 ui_->dockWidget_info->setVisible(
false);
148 ui_->dockWidget_stereoView->setVisible(
false);
149 ui_->dockWidget_view3d->setVisible(
false);
150 ui_->dockWidget_statistics->setVisible(
false);
170 ui_->graphicsView_stereo->setAlpha(255);
172 #ifndef RTABMAP_OCTOMAP 173 ui_->checkBox_octomap->setEnabled(
false);
174 ui_->checkBox_octomap->setChecked(
false);
198 ui_->parameters_toolbox->setupUi(parameters);
204 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
205 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
206 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
207 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
208 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
209 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
211 ui_->menuView->addAction(
ui_->dockWidget_constraints->toggleViewAction());
212 ui_->menuView->addAction(
ui_->dockWidget_graphView->toggleViewAction());
213 ui_->menuView->addAction(
ui_->dockWidget_occupancyGridView->toggleViewAction());
214 ui_->menuView->addAction(
ui_->dockWidget_stereoView->toggleViewAction());
215 ui_->menuView->addAction(
ui_->dockWidget_view3d->toggleViewAction());
216 ui_->menuView->addAction(
ui_->dockWidget_guiparameters->toggleViewAction());
217 ui_->menuView->addAction(
ui_->dockWidget_coreparameters->toggleViewAction());
218 ui_->menuView->addAction(
ui_->dockWidget_info->toggleViewAction());
219 ui_->menuView->addAction(
ui_->dockWidget_statistics->toggleViewAction());
220 connect(
ui_->dockWidget_graphView->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateGraphView()));
221 connect(
ui_->dockWidget_occupancyGridView->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateGraphView()));
222 connect(
ui_->dockWidget_statistics->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(
updateStatistics()));
225 connect(
ui_->parameters_toolbox, SIGNAL(parametersChanged(
const QStringList &)),
this, SLOT(
notifyParametersChanged(
const QStringList &)));
227 connect(
ui_->actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
229 ui_->actionOpen_database->setEnabled(
true);
230 ui_->actionClose_database->setEnabled(
false);
233 ui_->actionSave_config->setShortcut(QKeySequence::Save);
234 connect(
ui_->actionSave_config, SIGNAL(triggered()),
this, SLOT(
writeSettings()));
235 connect(
ui_->actionOpen_database, SIGNAL(triggered()),
this, SLOT(
openDatabase()));
236 connect(
ui_->actionClose_database, SIGNAL(triggered()),
this, SLOT(
closeDatabase()));
237 connect(
ui_->actionDatabase_recovery, SIGNAL(triggered()),
this, SLOT(
recoverDatabase()));
239 connect(
ui_->actionExtract_images, SIGNAL(triggered()),
this, SLOT(
extractImages()));
240 connect(
ui_->actionEdit_depth_image, SIGNAL(triggered()),
this, SLOT(
editDepthImage()));
241 connect(
ui_->actionGenerate_graph_dot, SIGNAL(triggered()),
this, SLOT(
generateGraph()));
243 connect(
ui_->actionRaw_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesRaw()));
245 connect(
ui_->actionKITTI_format_txt, SIGNAL(triggered()),
this , SLOT(
exportPosesKITTI()));
248 connect(
ui_->actionPoses_KML, SIGNAL(triggered()),
this , SLOT(
exportPosesKML()));
249 connect(
ui_->actionGPS_TXT, SIGNAL(triggered()),
this , SLOT(
exportGPS_TXT()));
250 connect(
ui_->actionGPS_KML, SIGNAL(triggered()),
this , SLOT(
exportGPS_KML()));
251 connect(
ui_->actionExport_saved_2D_map, SIGNAL(triggered()),
this , SLOT(
exportSaved2DMap()));
252 connect(
ui_->actionImport_2D_map, SIGNAL(triggered()),
this , SLOT(
import2DMap()));
256 connect(
ui_->actionView_3D_map, SIGNAL(triggered()),
this, SLOT(
view3DMap()));
257 connect(
ui_->actionGenerate_3D_map_pcd, SIGNAL(triggered()),
this, SLOT(
generate3DMap()));
263 connect(
ui_->actionReset_all_changes, SIGNAL(triggered()),
this, SLOT(
resetAllChanges()));
268 connect(
ui_->pushButton_add, SIGNAL(clicked()),
this, SLOT(
addConstraint()));
271 ui_->pushButton_refine->setEnabled(
false);
272 ui_->pushButton_add->setEnabled(
false);
273 ui_->pushButton_reset->setEnabled(
false);
274 ui_->pushButton_reject->setEnabled(
false);
276 ui_->menuEdit->setEnabled(
false);
277 ui_->actionGenerate_3D_map_pcd->setEnabled(
false);
278 ui_->actionExport->setEnabled(
false);
279 ui_->actionExtract_images->setEnabled(
false);
280 ui_->menuExport_poses->setEnabled(
false);
281 ui_->menuExport_GPS->setEnabled(
false);
282 ui_->actionPoses_KML->setEnabled(
false);
283 ui_->actionExport_saved_2D_map->setEnabled(
false);
284 ui_->actionView_optimized_mesh->setEnabled(
false);
285 ui_->actionExport_optimized_mesh->setEnabled(
false);
286 ui_->actionUpdate_optimized_mesh->setEnabled(
false);
288 ui_->horizontalSlider_A->setTracking(
false);
289 ui_->horizontalSlider_B->setTracking(
false);
290 ui_->horizontalSlider_A->setEnabled(
false);
291 ui_->horizontalSlider_B->setEnabled(
false);
294 connect(
ui_->horizontalSlider_A, SIGNAL(sliderMoved(
int)),
this, SLOT(
sliderAMoved(
int)));
295 connect(
ui_->horizontalSlider_B, SIGNAL(sliderMoved(
int)),
this, SLOT(
sliderBMoved(
int)));
297 connect(
ui_->spinBox_mesh_angleTolerance, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
298 connect(
ui_->spinBox_mesh_minClusterSize, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
299 connect(
ui_->spinBox_mesh_fillDepthHoles, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
300 connect(
ui_->spinBox_mesh_depthError, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
301 connect(
ui_->checkBox_mesh_quad, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
302 connect(
ui_->spinBox_mesh_triangleSize, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
303 connect(
ui_->checkBox_showWords, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
304 connect(
ui_->checkBox_showCloud, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
305 connect(
ui_->checkBox_showMesh, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
306 connect(
ui_->checkBox_showScan, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
307 connect(
ui_->checkBox_showMap, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
308 connect(
ui_->checkBox_showGrid, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
309 connect(
ui_->checkBox_odomFrame_3dview, SIGNAL(toggled(
bool)),
this, SLOT(
update3dView()));
311 ui_->horizontalSlider_neighbors->setTracking(
false);
312 ui_->horizontalSlider_loops->setTracking(
false);
313 ui_->horizontalSlider_neighbors->setEnabled(
false);
314 ui_->horizontalSlider_loops->setEnabled(
false);
324 ui_->checkBox_showOptimized->setEnabled(
false);
326 ui_->horizontalSlider_iterations->setTracking(
false);
327 ui_->horizontalSlider_iterations->setEnabled(
false);
328 ui_->spinBox_optimizationsFrom->setEnabled(
false);
331 connect(
ui_->spinBox_optimizationsFrom, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
332 connect(
ui_->checkBox_iterativeOptimization, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
333 connect(
ui_->checkBox_spanAllMaps, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
334 connect(
ui_->checkBox_wmState, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
335 connect(
ui_->graphViewer, SIGNAL(mapShownRequested()),
this, SLOT(
updateGraphView()));
336 connect(
ui_->checkBox_ignorePoseCorrection, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
338 connect(
ui_->checkBox_ignoreGlobalLoop, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
339 connect(
ui_->checkBox_ignoreLocalLoopSpace, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
340 connect(
ui_->checkBox_ignoreLocalLoopTime, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
341 connect(
ui_->checkBox_ignoreUserLoop, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
342 connect(
ui_->spinBox_optimizationDepth, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
343 connect(
ui_->doubleSpinBox_optimizationScale, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
344 connect(
ui_->checkBox_octomap, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
345 connect(
ui_->checkBox_grid_2d, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
346 connect(
ui_->comboBox_octomap_rendering_type, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
updateOctomapView()));
348 connect(
ui_->checkBox_grid_empty, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGrid()));
349 connect(
ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
updateConstraintView()));
351 connect(
ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(
double)),
this, SLOT(
update3dView()));
353 connect(
ui_->spinBox_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
update3dView()));
354 connect(
ui_->groupBox_posefiltering, SIGNAL(clicked(
bool)),
this, SLOT(
updateGraphView()));
355 connect(
ui_->doubleSpinBox_posefilteringRadius, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
356 connect(
ui_->doubleSpinBox_posefilteringAngle, SIGNAL(editingFinished()),
this, SLOT(
updateGraphView()));
358 ui_->label_stereo_inliers_name->setStyleSheet(
"QLabel {color : blue; }");
359 ui_->label_stereo_flowOutliers_name->setStyleSheet(
"QLabel {color : red; }");
360 ui_->label_stereo_slopeOutliers_name->setStyleSheet(
"QLabel {color : yellow; }");
361 ui_->label_stereo_disparityOutliers_name->setStyleSheet(
"QLabel {color : magenta; }");
365 connect(
ui_->graphViewer, SIGNAL(configChanged()),
this, SLOT(
configModified()));
368 connect(
ui_->comboBox_logger_level, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
configModified()));
369 connect(
ui_->actionVertical_Layout, SIGNAL(toggled(
bool)),
this, SLOT(
configModified()));
370 connect(
ui_->checkBox_alignPosesWithGroundTruth, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
371 connect(
ui_->checkBox_alignScansCloudsWithGroundTruth, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
372 connect(
ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
373 connect(
ui_->checkBox_ignoreIntermediateNodes, SIGNAL(stateChanged(
int)),
this, SLOT(
updateGraphView()));
374 connect(
ui_->checkBox_timeStats, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
375 connect(
ui_->checkBox_timeStats, SIGNAL(stateChanged(
int)),
this, SLOT(
updateStatistics()));
377 connect(
ui_->doubleSpinBox_gainCompensationRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
378 connect(
ui_->doubleSpinBox_voxelSize, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
379 connect(
ui_->spinBox_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
380 connect(
ui_->groupBox_posefiltering, SIGNAL(clicked(
bool)),
this, SLOT(
configModified()));
381 connect(
ui_->doubleSpinBox_posefilteringRadius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
382 connect(
ui_->doubleSpinBox_posefilteringAngle, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
384 connect(
ui_->spinBox_icp_decimation, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
385 connect(
ui_->doubleSpinBox_icp_maxDepth, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
386 connect(
ui_->doubleSpinBox_icp_minDepth, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
387 connect(
ui_->checkBox_icp_from_depth, SIGNAL(stateChanged(
int)),
this, SLOT(
configModified()));
389 connect(
ui_->doubleSpinBox_detectMore_radius, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
390 connect(
ui_->doubleSpinBox_detectMore_angle, SIGNAL(valueChanged(
double)),
this, SLOT(
configModified()));
391 connect(
ui_->spinBox_detectMore_iterations, SIGNAL(valueChanged(
int)),
this, SLOT(
configModified()));
393 connect(
ui_->lineEdit_obstacleColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
394 connect(
ui_->lineEdit_groundColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
395 connect(
ui_->lineEdit_emptyColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
configModified()));
396 connect(
ui_->lineEdit_obstacleColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
397 connect(
ui_->lineEdit_groundColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
398 connect(
ui_->lineEdit_emptyColor, SIGNAL(textChanged(
const QString &)),
this, SLOT(
updateGrid()));
401 connect(
ui_->toolButton_emptyColor, SIGNAL(clicked(
bool)),
this, SLOT(
selectEmptyColor()));
406 QList<QDockWidget*> dockWidgets = this->findChildren<QDockWidget*>();
407 for(
int i=0; i<dockWidgets.size(); ++i)
409 connect(dockWidgets[i], SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
this, SLOT(
configModified()));
410 connect(dockWidgets[i]->toggleViewAction(), SIGNAL(toggled(
bool)),
this, SLOT(
configModified()));
412 ui_->dockWidget_constraints->installEventFilter(
this);
413 ui_->dockWidget_graphView->installEventFilter(
this);
414 ui_->dockWidget_occupancyGridView->installEventFilter(
this);
415 ui_->dockWidget_stereoView->installEventFilter(
this);
416 ui_->dockWidget_view3d->installEventFilter(
this);
417 ui_->dockWidget_guiparameters->installEventFilter(
this);
418 ui_->dockWidget_coreparameters->installEventFilter(
this);
419 ui_->dockWidget_info->installEventFilter(
this);
420 ui_->dockWidget_statistics->installEventFilter(
this);
427 #ifdef RTABMAP_OCTOMAP 436 qobject_cast<QHBoxLayout *>(
ui_->horizontalLayout_imageViews->layout())->setDirection(QBoxLayout::TopToBottom);
440 qobject_cast<QHBoxLayout *>(
ui_->horizontalLayout_imageViews->layout())->setDirection(QBoxLayout::LeftToRight);
450 ui_->buttonBox->setVisible(visible);
455 this->setWindowModified(
true);
464 QString privatePath = QDir::homePath() +
"/.rtabmap";
465 if(!QDir(privatePath).exists())
467 QDir::home().mkdir(
".rtabmap");
469 return privatePath +
"/rtabmap.ini";
475 QSettings settings(path, QSettings::IniFormat);
476 settings.beginGroup(
"DatabaseViewer");
480 bytes = settings.value(
"geometry", QByteArray()).toByteArray();
483 this->restoreGeometry(bytes);
485 bytes = settings.value(
"state", QByteArray()).toByteArray();
488 this->restoreState(bytes);
492 ui_->comboBox_logger_level->setCurrentIndex(settings.value(
"loggerLevel",
ui_->comboBox_logger_level->currentIndex()).toInt());
493 ui_->actionVertical_Layout->setChecked(settings.value(
"verticalLayout",
ui_->actionVertical_Layout->isChecked()).toBool());
494 ui_->checkBox_ignoreIntermediateNodes->setChecked(settings.value(
"ignoreIntermediateNodes",
ui_->checkBox_ignoreIntermediateNodes->isChecked()).toBool());
495 ui_->checkBox_timeStats->setChecked(settings.value(
"timeStats",
ui_->checkBox_timeStats->isChecked()).toBool());
498 ui_->graphViewer->loadSettings(settings,
"GraphView");
500 settings.beginGroup(
"optimization");
501 ui_->doubleSpinBox_gainCompensationRadius->setValue(settings.value(
"gainCompensationRadius",
ui_->doubleSpinBox_gainCompensationRadius->value()).toDouble());
502 ui_->doubleSpinBox_voxelSize->setValue(settings.value(
"voxelSize",
ui_->doubleSpinBox_voxelSize->value()).toDouble());
503 ui_->spinBox_decimation->setValue(settings.value(
"decimation",
ui_->spinBox_decimation->value()).toInt());
506 settings.beginGroup(
"grid");
507 ui_->groupBox_posefiltering->setChecked(settings.value(
"poseFiltering",
ui_->groupBox_posefiltering->isChecked()).toBool());
508 ui_->doubleSpinBox_posefilteringRadius->setValue(settings.value(
"poseFilteringRadius",
ui_->doubleSpinBox_posefilteringRadius->value()).toDouble());
509 ui_->doubleSpinBox_posefilteringAngle->setValue(settings.value(
"poseFilteringAngle",
ui_->doubleSpinBox_posefilteringAngle->value()).toDouble());
510 ui_->lineEdit_obstacleColor->setText(settings.value(
"colorObstacle",
ui_->lineEdit_obstacleColor->text()).toString());
511 ui_->lineEdit_groundColor->setText(settings.value(
"colorGround",
ui_->lineEdit_groundColor->text()).toString());
512 ui_->lineEdit_emptyColor->setText(settings.value(
"colorEmpty",
ui_->lineEdit_emptyColor->text()).toString());
515 settings.beginGroup(
"mesh");
516 ui_->checkBox_mesh_quad->setChecked(settings.value(
"quad",
ui_->checkBox_mesh_quad->isChecked()).toBool());
517 ui_->spinBox_mesh_angleTolerance->setValue(settings.value(
"angleTolerance",
ui_->spinBox_mesh_angleTolerance->value()).toInt());
518 ui_->spinBox_mesh_minClusterSize->setValue(settings.value(
"minClusterSize",
ui_->spinBox_mesh_minClusterSize->value()).toInt());
519 ui_->spinBox_mesh_fillDepthHoles->setValue(settings.value(
"fillDepthHolesSize",
ui_->spinBox_mesh_fillDepthHoles->value()).toInt());
520 ui_->spinBox_mesh_depthError->setValue(settings.value(
"fillDepthHolesError",
ui_->spinBox_mesh_depthError->value()).toInt());
521 ui_->spinBox_mesh_triangleSize->setValue(settings.value(
"triangleSize",
ui_->spinBox_mesh_triangleSize->value()).toInt());
529 settings.beginGroup(
"icp");
530 ui_->spinBox_icp_decimation->setValue(settings.value(
"decimation",
ui_->spinBox_icp_decimation->value()).toInt());
531 ui_->doubleSpinBox_icp_maxDepth->setValue(settings.value(
"maxDepth",
ui_->doubleSpinBox_icp_maxDepth->value()).toDouble());
532 ui_->doubleSpinBox_icp_minDepth->setValue(settings.value(
"minDepth",
ui_->doubleSpinBox_icp_minDepth->value()).toDouble());
533 ui_->checkBox_icp_from_depth->setChecked(settings.value(
"icpFromDepth",
ui_->checkBox_icp_from_depth->isChecked()).toBool());
539 settings.beginGroup(
"Gui");
541 settings.beginGroup(
"PostProcessingDialog");
542 ui_->doubleSpinBox_detectMore_radius->setValue(settings.value(
"cluster_radius",
ui_->doubleSpinBox_detectMore_radius->value()).toDouble());
543 ui_->doubleSpinBox_detectMore_angle->setValue(settings.value(
"cluster_angle",
ui_->doubleSpinBox_detectMore_angle->value()).toDouble());
544 ui_->spinBox_detectMore_iterations->setValue(settings.value(
"iterations",
ui_->spinBox_detectMore_iterations->value()).toInt());
551 for(ParametersMap::iterator iter = parameters.begin(); iter!= parameters.end(); ++iter)
553 ui_->parameters_toolbox->updateParameter(iter->first, iter->second);
560 QSettings settings(path, QSettings::IniFormat);
561 settings.beginGroup(
"DatabaseViewer");
564 if(!this->isMaximized())
566 settings.setValue(
"geometry", this->saveGeometry());
568 settings.setValue(
"state", this->saveState());
569 settings.setValue(
"maximized", this->isMaximized());
572 settings.setValue(
"loggerLevel",
ui_->comboBox_logger_level->currentIndex());
573 settings.setValue(
"verticalLayout",
ui_->actionVertical_Layout->isChecked());
574 settings.setValue(
"ignoreIntermediateNodes",
ui_->checkBox_ignoreIntermediateNodes->isChecked());
575 settings.setValue(
"timeStats",
ui_->checkBox_timeStats->isChecked());
578 ui_->graphViewer->saveSettings(settings,
"GraphView");
581 settings.beginGroup(
"optimization");
582 settings.setValue(
"gainCompensationRadius",
ui_->doubleSpinBox_gainCompensationRadius->value());
583 settings.setValue(
"voxelSize",
ui_->doubleSpinBox_voxelSize->value());
584 settings.setValue(
"decimation",
ui_->spinBox_decimation->value());
588 settings.beginGroup(
"grid");
589 settings.setValue(
"poseFiltering",
ui_->groupBox_posefiltering->isChecked());
590 settings.setValue(
"poseFilteringRadius",
ui_->doubleSpinBox_posefilteringRadius->value());
591 settings.setValue(
"poseFilteringAngle",
ui_->doubleSpinBox_posefilteringAngle->value());
592 settings.setValue(
"colorObstacle",
ui_->lineEdit_obstacleColor->text());
593 settings.setValue(
"colorGround",
ui_->lineEdit_groundColor->text());
594 settings.setValue(
"colorEmpty",
ui_->lineEdit_emptyColor->text());
597 settings.beginGroup(
"mesh");
598 settings.setValue(
"quad",
ui_->checkBox_mesh_quad->isChecked());
599 settings.setValue(
"angleTolerance",
ui_->spinBox_mesh_angleTolerance->value());
600 settings.setValue(
"minClusterSize",
ui_->spinBox_mesh_minClusterSize->value());
601 settings.setValue(
"fillDepthHolesSize",
ui_->spinBox_mesh_fillDepthHoles->value());
602 settings.setValue(
"fillDepthHolesError",
ui_->spinBox_mesh_depthError->value());
603 settings.setValue(
"triangleSize",
ui_->spinBox_mesh_triangleSize->value());
611 settings.beginGroup(
"icp");
612 settings.setValue(
"decimation",
ui_->spinBox_icp_decimation->value());
613 settings.setValue(
"maxDepth",
ui_->doubleSpinBox_icp_maxDepth->value());
614 settings.setValue(
"minDepth",
ui_->doubleSpinBox_icp_minDepth->value());
615 settings.setValue(
"icpFromDepth",
ui_->checkBox_icp_from_depth->isChecked());
621 settings.beginGroup(
"Gui");
623 settings.beginGroup(
"PostProcessingDialog");
624 settings.setValue(
"cluster_radius",
ui_->doubleSpinBox_detectMore_radius->value());
625 settings.setValue(
"cluster_angle",
ui_->doubleSpinBox_detectMore_angle->value());
626 settings.setValue(
"iterations",
ui_->spinBox_detectMore_iterations->value());
631 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end();)
633 if(!
ui_->parameters_toolbox->getParameterWidget(iter->first.c_str()))
635 parameters.erase(iter++);
644 this->setWindowModified(
false);
650 ui_->comboBox_logger_level->setCurrentIndex(1);
651 ui_->checkBox_alignPosesWithGroundTruth->setChecked(
true);
652 ui_->checkBox_alignScansCloudsWithGroundTruth->setChecked(
false);
653 ui_->checkBox_ignoreIntermediateNodes->setChecked(
false);
654 ui_->checkBox_timeStats->setChecked(
true);
656 ui_->checkBox_iterativeOptimization->setChecked(
true);
657 ui_->checkBox_spanAllMaps->setChecked(
true);
658 ui_->checkBox_wmState->setChecked(
false);
659 ui_->checkBox_ignorePoseCorrection->setChecked(
false);
660 ui_->checkBox_ignoreGlobalLoop->setChecked(
false);
661 ui_->checkBox_ignoreLocalLoopSpace->setChecked(
false);
662 ui_->checkBox_ignoreLocalLoopTime->setChecked(
false);
663 ui_->checkBox_ignoreUserLoop->setChecked(
false);
664 ui_->spinBox_optimizationDepth->setValue(0);
665 ui_->doubleSpinBox_optimizationScale->setValue(1.0);
666 ui_->doubleSpinBox_gainCompensationRadius->setValue(0.0);
667 ui_->doubleSpinBox_voxelSize->setValue(0.0);
668 ui_->spinBox_decimation->setValue(1);
670 ui_->groupBox_posefiltering->setChecked(
false);
671 ui_->doubleSpinBox_posefilteringRadius->setValue(0.1);
672 ui_->doubleSpinBox_posefilteringAngle->setValue(30);
673 ui_->checkBox_grid_empty->setChecked(
true);
674 ui_->checkBox_octomap->setChecked(
false);
675 ui_->lineEdit_obstacleColor->setText(QColor(Qt::red).name());
676 ui_->lineEdit_groundColor->setText(QColor(Qt::green).name());
677 ui_->lineEdit_emptyColor->setText(QColor(Qt::yellow).name());
679 ui_->checkBox_mesh_quad->setChecked(
true);
680 ui_->spinBox_mesh_angleTolerance->setValue(15);
681 ui_->spinBox_mesh_minClusterSize->setValue(0);
682 ui_->spinBox_mesh_fillDepthHoles->setValue(
false);
683 ui_->spinBox_mesh_depthError->setValue(10);
684 ui_->spinBox_mesh_triangleSize->setValue(2);
686 ui_->spinBox_icp_decimation->setValue(1);
687 ui_->doubleSpinBox_icp_maxDepth->setValue(0.0);
688 ui_->doubleSpinBox_icp_minDepth->setValue(0.0);
689 ui_->checkBox_icp_from_depth->setChecked(
false);
691 ui_->doubleSpinBox_detectMore_radius->setValue(1.0);
692 ui_->doubleSpinBox_detectMore_angle->setValue(30.0);
693 ui_->spinBox_detectMore_iterations->setValue(5);
698 QString path = QFileDialog::getOpenFileName(
this, tr(
"Select file"),
pathDatabase_, tr(
"Databases (*.db)"));
707 UDEBUG(
"Open database \"%s\"", path.toStdString().c_str());
708 if(QFile::exists(path))
710 if(QFileInfo(path).isFile())
712 std::string driverType =
"sqlite3";
718 ui_->actionClose_database->setEnabled(
false);
719 ui_->actionOpen_database->setEnabled(
true);
722 QMessageBox::warning(
this,
"Database error", tr(
"Can't open database \"%1\"").arg(path));
726 ui_->actionClose_database->setEnabled(
true);
727 ui_->actionOpen_database->setEnabled(
false);
740 if(parameters.size())
742 const ParametersMap & currentParameters =
ui_->parameters_toolbox->getParameters();
744 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
746 ParametersMap::const_iterator jter = currentParameters.find(iter->first);
747 if(jter!=currentParameters.end() &&
748 ui_->parameters_toolbox->getParameterWidget(QString(iter->first.c_str())) != 0 &&
749 iter->second.compare(jter->second) != 0 &&
750 iter->first.compare(Parameters::kRtabmapWorkingDirectory()) != 0)
752 bool different =
true;
763 differentParameters.insert(*iter);
764 QString msg = tr(
"Parameter \"%1\": database=\"%2\" Preferences=\"%3\"")
765 .arg(iter->first.c_str())
766 .arg(iter->second.c_str())
767 .arg(jter->second.c_str());
768 UWARN(msg.toStdString().c_str());
773 if(differentParameters.size())
775 int r = QMessageBox::question(
this,
776 tr(
"Update parameters..."),
777 tr(
"The database is using %1 different parameter(s) than " 778 "those currently set in Core parameters panel. Do you want " 779 "to use database's parameters?").arg(differentParameters.size()),
780 QMessageBox::Yes | QMessageBox::No,
782 if(r == QMessageBox::Yes)
785 for(rtabmap::ParametersMap::const_iterator iter = differentParameters.begin(); iter!=differentParameters.end(); ++iter)
787 ui_->parameters_toolbox->updateParameter(iter->first, iter->second);
788 str.push_back(iter->first.c_str());
811 QMessageBox::warning(
this,
"Database error", tr(
"Database \"%1\" does not exist.").arg(path));
822 QMessageBox::StandardButton button = QMessageBox::question(
this,
823 tr(
"Links modified"),
824 tr(
"Some links are modified (%1 added, %2 refined, %3 removed), do you want to save them?")
826 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
827 QMessageBox::Cancel);
829 if(button == QMessageBox::Yes)
832 for(std::multimap<int, rtabmap::Link>::iterator iter=
linksAdded_.begin(); iter!=
linksAdded_.end(); ++iter)
868 if(button != QMessageBox::Yes && button != QMessageBox::No)
877 QMessageBox::StandardButton button = QMessageBox::question(
this,
878 tr(
"Local occupancy grid maps modified"),
879 tr(
"%1 occupancy grid maps are modified, do you want to " 880 "save them? This will overwrite occupancy grids saved in the database.")
882 QMessageBox::Cancel | QMessageBox::Yes | QMessageBox::No,
883 QMessageBox::Cancel);
885 if(button == QMessageBox::Yes)
889 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat > >::iterator mapIter =
generatedLocalMaps_.begin();
893 UASSERT(mapIter->first == infoIter->first);
896 mapIter->second.first.first,
897 mapIter->second.first.second,
898 mapIter->second.second,
899 infoIter->second.first,
900 infoIter->second.second);
908 if(button != QMessageBox::Yes && button != QMessageBox::No)
937 ui_->graphViewer->clearAll();
939 ui_->menuEdit->setEnabled(
false);
940 ui_->actionGenerate_3D_map_pcd->setEnabled(
false);
941 ui_->actionExport->setEnabled(
false);
942 ui_->actionExtract_images->setEnabled(
false);
943 ui_->menuExport_poses->setEnabled(
false);
944 ui_->menuExport_GPS->setEnabled(
false);
945 ui_->actionPoses_KML->setEnabled(
false);
946 ui_->actionExport_saved_2D_map->setEnabled(
false);
947 ui_->actionImport_2D_map->setEnabled(
false);
948 ui_->actionView_optimized_mesh->setEnabled(
false);
949 ui_->actionExport_optimized_mesh->setEnabled(
false);
950 ui_->actionUpdate_optimized_mesh->setEnabled(
false);
951 ui_->checkBox_showOptimized->setEnabled(
false);
952 ui_->toolBox_statistics->clear();
954 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
false);
955 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
false);
956 ui_->doubleSpinBox_optimizationScale->setVisible(
false);
957 ui_->label_scale_title->setVisible(
false);
958 ui_->label_rmse->setVisible(
false);
959 ui_->label_rmse_title->setVisible(
false);
960 ui_->checkBox_ignoreIntermediateNodes->setVisible(
false);
961 ui_->label_ignoreINtermediateNdoes->setVisible(
false);
962 ui_->label_alignPosesWithGroundTruth->setVisible(
false);
963 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
false);
964 ui_->label_optimizeFrom->setText(tr(
"Root"));
965 ui_->textEdit_info->clear();
967 ui_->pushButton_refine->setEnabled(
false);
968 ui_->pushButton_add->setEnabled(
false);
969 ui_->pushButton_reset->setEnabled(
false);
970 ui_->pushButton_reject->setEnabled(
false);
972 ui_->horizontalSlider_loops->setEnabled(
false);
973 ui_->horizontalSlider_loops->setMaximum(0);
974 ui_->horizontalSlider_iterations->setEnabled(
false);
975 ui_->horizontalSlider_iterations->setMaximum(0);
976 ui_->horizontalSlider_neighbors->setEnabled(
false);
977 ui_->horizontalSlider_neighbors->setMaximum(0);
978 ui_->label_constraint->clear();
979 ui_->label_constraint_opt->clear();
980 ui_->label_variance->clear();
981 ui_->lineEdit_covariance->clear();
983 ui_->horizontalSlider_A->setEnabled(
false);
984 ui_->horizontalSlider_A->setMaximum(0);
985 ui_->horizontalSlider_B->setEnabled(
false);
986 ui_->horizontalSlider_B->setMaximum(0);
987 ui_->label_idA->setText(
"NaN");
988 ui_->label_idB->setText(
"NaN");
1001 ui_->graphViewer->clearAll();
1002 ui_->label_loopClosures->clear();
1003 ui_->label_timeOptimization->clear();
1004 ui_->label_pathLength->clear();
1005 ui_->label_poses->clear();
1006 ui_->label_rmse->clear();
1007 ui_->spinBox_optimizationsFrom->setEnabled(
false);
1009 ui_->graphicsView_A->clear();
1010 ui_->graphicsView_B->clear();
1012 ui_->graphicsView_stereo->clear();
1016 ui_->toolBox_statistics->clear();
1031 QString path = QFileDialog::getOpenFileName(
this, tr(
"Select file"),
pathDatabase_, tr(
"Databases (*.db)"));
1036 QMessageBox::information(
this,
"Database recovery", tr(
"The selected database is already opened, close it first."));
1039 std::string errorMsg;
1041 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1043 progressDialog->show();
1048 QMessageBox::information(
this,
"Database recovery", tr(
"Database \"%1\" recovered! Try opening it again.").arg(path));
1052 QMessageBox::warning(
this,
"Database recovery", tr(
"Database recovery failed: \"%1\".").arg(errorMsg.c_str()));
1062 if(this->isWindowModified())
1064 QMessageBox::Button b=QMessageBox::question(
this,
1065 tr(
"Database Viewer"),
1066 tr(
"There are unsaved changed settings. Save them?"),
1067 QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard);
1068 if(b == QMessageBox::Save)
1072 else if(b != QMessageBox::Discard)
1091 if(event->isAccepted())
1093 ui_->toolBox_statistics->closeFigures();
1104 this->setWindowModified(
false);
1106 if((
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible()) &&
graphes_.size() &&
localMaps_.size()==0)
1114 if(this->isVisible())
1127 if(this->isVisible())
1136 if((event->modifiers() & Qt::ControlModifier) && event->key() == Qt::Key_S)
1144 if (event->type() == QEvent::Resize && qobject_cast<QDockWidget*>(obj))
1146 this->setWindowModified(
true);
1148 return QWidget::eventFilter(obj, event);
1172 double previousStamp = 0;
1173 std::vector<double> delays(
ids_.size());
1175 std::map<int, Transform> poses;
1176 std::map<int, double> stamps;
1177 std::map<int, Transform> groundTruths;
1178 std::map<int, GPS> gpsValues;
1179 for(
int i=0; i<
ids_.size(); i+=1+framesIgnored)
1186 std::vector<float> velocity;
1190 if(frameRate == 0 ||
1191 previousStamp == 0 ||
1193 stamp - previousStamp >= 1.0/frameRate)
1195 if(sessionExported < 0 || sessionExported == mapId)
1197 ids.push_back(
ids_[i]);
1199 if(previousStamp && stamp)
1201 delays[oi++] = stamp - previousStamp;
1203 previousStamp = stamp;
1205 poses.insert(std::make_pair(
ids_[i], odomPose));
1206 stamps.insert(std::make_pair(
ids_[i], stamp));
1207 groundTruths.insert(std::make_pair(
ids_[i], groundTruth));
1208 if(gps.
stamp() > 0.0)
1210 gpsValues.insert(std::make_pair(
ids_[i], gps));
1214 if(sessionExported >= 0 && mapId > sessionExported)
1222 if(recorder.
init(path,
false))
1225 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
1227 progressDialog->show();
1229 UINFO(
"Decompress: rgb=%d depth=%d scan=%d userData=%d",
1235 for(
int i=0; i<ids.size() && !progressDialog->
isCanceled(); ++i)
1241 cv::Mat depth, rgb, userData;
1248 cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
1251 std::map<int, Link> links;
1253 if(links.size() && links.begin()->first < id)
1255 covariance = links.begin()->second.infMatrix().inv();
1282 if(groundTruths.find(
id)!=groundTruths.end())
1286 if(gpsValues.find(
id)!=gpsValues.end())
1288 sensorData.
setGPS(gpsValues.at(
id));
1293 progressDialog->
appendText(tr(
"Exported node %1").arg(
id));
1295 QApplication::processEvents();
1300 progressDialog->
appendText(tr(
"Average frame rate=%1 Hz (Min=%2, Max=%3)")
1301 .arg(1.0/
uMean(delays)).arg(1.0/
uMax(delays)).arg(1.0/
uMin(delays)));
1303 progressDialog->
appendText(tr(
"Export finished to \"%1\"!").arg(path));
1307 UERROR(
"DataRecorder init failed?!");
1312 QMessageBox::warning(
this, tr(
"Cannot export database"), tr(
"An output path must be set!"));
1324 QStringList formats;
1325 formats.push_back(
"jpg");
1326 formats.push_back(
"png");
1328 QString ext = QInputDialog::getItem(
this, tr(
"Which RGB format?"), tr(
"Format:"), formats, 0,
false, &ok);
1334 QString path = QFileDialog::getExistingDirectory(
this, tr(
"Select directory where to save images..."), QDir::homePath());
1339 int id =
ids_.at(0);
1346 dir.mkdir(QString(
"%1/left").arg(path));
1347 dir.mkdir(QString(
"%1/right").arg(path));
1350 UERROR(
"Cannot save calibration file, database name is empty!");
1372 if(model.save(path.toStdString()))
1374 UINFO(
"Saved stereo calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1378 UERROR(
"Failed saving calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1387 dir.mkdir(QString(
"%1/rgb").arg(path));
1388 dir.mkdir(QString(
"%1/depth").arg(path));
1393 UERROR(
"Cannot save calibration file, database name is empty!");
1397 UERROR(
"Only one camera calibration can be saved at this time (%d detected)", (
int)data.
cameraModels().size());
1409 if(model.save(path.toStdString()))
1411 UINFO(
"Saved calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1415 UERROR(
"Failed saving calibration \"%s\"", (path.toStdString()+
"/"+cameraName).c_str());
1421 int imagesExported = 0;
1422 for(
int i=0; i<
ids_.size(); ++i)
1424 int id =
ids_.at(i);
1430 cv::imwrite(QString(
"%1/left/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
imageRaw());
1431 cv::imwrite(QString(
"%1/right/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
rightRaw());
1432 UINFO(QString(
"Saved left/%1.%2 and right/%1.%2").arg(
id).arg(ext).toStdString().c_str());
1437 cv::imwrite(QString(
"%1/rgb/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
imageRaw());
1439 UINFO(QString(
"Saved rgb/%1.%2 and depth/%1.png").arg(
id).arg(ext).toStdString().c_str());
1444 cv::imwrite(QString(
"%1/%2.%3").arg(path).arg(
id).arg(ext).toStdString(), data.
imageRaw());
1445 UINFO(QString(
"Saved %1.%2").arg(
id).arg(ext).toStdString().c_str());
1449 QMessageBox::information(
this, tr(
"Exporting"), tr(
"%1 images exported!").arg(imagesExported));
1460 UINFO(
"Loading all IDs...");
1463 ids_ = QList<int>::fromStdList(std::list<int>(ids.begin(), ids.end()));
1472 ui_->checkBox_wmState->setVisible(
false);
1473 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
false);
1474 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
false);
1475 ui_->doubleSpinBox_optimizationScale->setVisible(
false);
1476 ui_->label_scale_title->setVisible(
false);
1477 ui_->label_rmse->setVisible(
false);
1478 ui_->label_rmse_title->setVisible(
false);
1479 ui_->checkBox_ignoreIntermediateNodes->setVisible(
false);
1480 ui_->label_ignoreINtermediateNdoes->setVisible(
false);
1481 ui_->label_alignPosesWithGroundTruth->setVisible(
false);
1482 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
false);
1483 ui_->menuEdit->setEnabled(
true);
1484 ui_->actionGenerate_3D_map_pcd->setEnabled(
true);
1485 ui_->actionExport->setEnabled(
true);
1486 ui_->actionExtract_images->setEnabled(
true);
1487 ui_->menuExport_poses->setEnabled(
false);
1488 ui_->menuExport_GPS->setEnabled(
false);
1489 ui_->actionPoses_KML->setEnabled(
false);
1490 ui_->actionExport_saved_2D_map->setEnabled(
false);
1491 ui_->actionImport_2D_map->setEnabled(
false);
1492 ui_->actionView_optimized_mesh->setEnabled(
false);
1493 ui_->actionExport_optimized_mesh->setEnabled(
false);
1499 ui_->toolBox_statistics->clear();
1500 ui_->label_optimizeFrom->setText(tr(
"Root"));
1501 std::multimap<int, Link> links;
1503 UDEBUG(
"%d total links loaded", (
int)links.size());
1505 double totalOdom = 0.0;
1507 int sessions =
ids_.size()?1:0;
1508 double totalTime = 0.0;
1509 double previousStamp = 0.0;
1510 std::set<int> idsWithoutBad;
1512 int badcountInLTM = 0;
1513 int badCountInGraph = 0;
1514 bool hasReducedGraph =
false;
1516 for(
int i=0; i<
ids_.size(); ++i)
1525 std::vector<float> v;
1530 if(wmStates.find(
ids_[i]) != wmStates.end())
1533 ui_->checkBox_wmState->setVisible(
true);
1537 ui_->checkBox_ignoreIntermediateNodes->setVisible(
true);
1538 ui_->label_ignoreINtermediateNdoes->setVisible(
true);
1549 if(previousStamp > 0.0 && s > 0.0)
1551 totalTime += s-previousStamp;
1563 bool addPose = links.find(
ids_[i]) == links.end();
1564 for(std::multimap<int, Link>::iterator jter=links.find(
ids_[i]); jter!=links.end() && jter->first ==
ids_[i]; ++jter)
1568 hasReducedGraph =
true;
1571 std::multimap<int, Link>::iterator invertedLinkIter =
graph::findLink(links, jter->second.to(), jter->second.from(),
false);
1572 if( jter->second.isValid() &&
1573 ids.find(jter->second.from()) != ids.end() &&
1574 ids.find(jter->second.to()) != ids.end() &&
1576 graph::findLink(links, jter->second.from(), jter->second.to(),
false) != links.end() &&
1577 invertedLinkIter != links.end())
1580 if(jter->second.userDataCompressed().cols == 0 &&
1581 invertedLinkIter->second.userDataCompressed().cols != 0)
1583 links_.insert(std::make_pair(invertedLinkIter->second.from(), invertedLinkIter->second));
1587 links_.insert(std::make_pair(
ids_[i], jter->second));
1603 if(gps.
stamp() > 0.0)
1607 cv::Point3f p(0.0
f,0.0
f,0.0
f);
1619 if(idsWithoutBad.find(
ids_[i]) == idsWithoutBad.end())
1631 ui_->checkBox_alignPosesWithGroundTruth->setVisible(
true);
1632 ui_->doubleSpinBox_optimizationScale->setVisible(
true);
1633 ui_->label_scale_title->setVisible(
true);
1634 ui_->label_rmse->setVisible(
true);
1635 ui_->label_rmse_title->setVisible(
true);
1636 ui_->label_alignPosesWithGroundTruth->setVisible(
true);
1640 ui_->label_alignPosesWithGroundTruth->setText(tr(
"Align poses with ground truth"));
1641 ui_->checkBox_alignScansCloudsWithGroundTruth->setVisible(
true);
1642 ui_->label_alignScansCloudsWithGroundTruth->setVisible(
true);
1646 ui_->label_alignPosesWithGroundTruth->setText(tr(
"Align poses with GPS"));
1651 ui_->menuExport_GPS->setEnabled(
true);
1655 float xMin, yMin, cellSize;
1657 ui_->actionExport_saved_2D_map->setEnabled(hasMap);
1658 ui_->actionImport_2D_map->setEnabled(hasMap);
1662 ui_->actionView_optimized_mesh->setEnabled(
true);
1663 ui_->actionExport_optimized_mesh->setEnabled(
true);
1668 if(
ids_.size() &&
ui_->toolBox_statistics->isVisible())
1670 UINFO(
"Update statistics...");
1674 UINFO(
"Update database info...");
1675 ui_->textEdit_info->clear();
1678 ui_->textEdit_info->append(tr(
"Sessions:\t\t%1").arg(sessions));
1681 ui_->textEdit_info->append(tr(
"Total odometry length:\t%1 m (approx. as graph has been reduced)").arg(totalOdom));
1685 ui_->textEdit_info->append(tr(
"Total odometry length:\t%1 m").arg(totalOdom));
1687 ui_->textEdit_info->append(tr(
"Total time:\t\t%1").arg(QDateTime::fromMSecsSinceEpoch(totalTime*1000).toUTC().toString(
"hh:mm:ss.zzz")));
1690 ui_->textEdit_info->append(tr(
"Global graph:\t%1 poses and %2 links").arg(
odomPoses_.size()).arg(
links_.size()));
1692 ui_->textEdit_info->append(tr(
"GPS:\t%1 poses").arg(
gpsValues_.size()));
1693 ui_->textEdit_info->append(
"");
1697 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"));
1700 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"));
1703 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"));
1706 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"));
1709 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"));
1712 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"));
1715 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"));
1718 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"));
1721 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"));
1724 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"));
1727 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"));
1730 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"));
1731 mem = dbSize - total;
1732 ui_->textEdit_info->append(tr(
"Other (indexing):\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"));
1733 ui_->textEdit_info->append(
"");
1734 ui_->textEdit_info->append(tr(
"%1 bad signatures in LTM").arg(badcountInLTM));
1735 ui_->textEdit_info->append(tr(
"%1 bad signatures in the global graph").arg(badCountInGraph));
1736 ui_->textEdit_info->append(
"");
1738 QFontMetrics metrics(
ui_->textEdit_info->font());
1739 int tabW =
ui_->textEdit_info->tabStopWidth();
1740 for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
1742 int strW = metrics.width(QString(iter->first.c_str()) +
"=");
1743 ui_->textEdit_info->append(tr(
"%1=%2%3")
1744 .arg(iter->first.c_str())
1745 .arg(strW < tabW?
"\t\t\t\t":strW < tabW*2?
"\t\t\t":strW < tabW*3?
"\t\t":
"\t")
1746 .arg(iter->second.c_str()));
1750 ui_->textEdit_info->moveCursor(QTextCursor::Start) ;
1751 ui_->textEdit_info->ensureCursorVisible() ;
1757 bool nullPoses =
odomPoses_.begin()->second.isNull();
1760 if((!iter->second.isNull() && nullPoses) ||
1761 (iter->second.isNull() && !nullPoses))
1763 if(iter->second.isNull())
1765 UWARN(
"Pose %d is null!", iter->first);
1767 UWARN(
"Mixed valid and null poses! Ignoring graph...");
1782 ui_->spinBox_optimizationsFrom->setValue(
odomPoses_.begin()->first);
1783 ui_->label_optimizeFrom->setText(tr(
"Root [%1, %2]").arg(
odomPoses_.begin()->first).arg(
odomPoses_.rbegin()->first));
1788 ui_->menuExport_poses->setEnabled(
false);
1793 for(std::multimap<int, rtabmap::Link>::iterator iter =
links_.begin(); iter!=
links_.end(); ++iter)
1795 if(!iter->second.transform().isNull())
1809 UERROR(
"Transform null for link from %d to %d", iter->first, iter->second.to());
1815 ui_->horizontalSlider_A->setMinimum(0);
1816 ui_->horizontalSlider_B->setMinimum(0);
1817 ui_->horizontalSlider_A->setMaximum(
ids_.size()-1);
1818 ui_->horizontalSlider_B->setMaximum(
ids_.size()-1);
1819 ui_->horizontalSlider_A->setEnabled(
true);
1820 ui_->horizontalSlider_B->setEnabled(
true);
1821 ui_->horizontalSlider_A->setSliderPosition(0);
1822 ui_->horizontalSlider_B->setSliderPosition(0);
1828 ui_->horizontalSlider_A->setEnabled(
false);
1829 ui_->horizontalSlider_B->setEnabled(
false);
1830 ui_->label_idA->setText(
"NaN");
1831 ui_->label_idB->setText(
"NaN");
1836 ui_->horizontalSlider_neighbors->setMinimum(0);
1838 ui_->horizontalSlider_neighbors->setEnabled(
true);
1839 ui_->horizontalSlider_neighbors->setSliderPosition(0);
1843 ui_->horizontalSlider_neighbors->setEnabled(
false);
1849 if(
ui_->graphViewer->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
1861 ui_->toolBox_statistics->clear();
1862 double firstStamp = 0.0;
1865 std::map<std::string, std::pair<std::vector<float>, std::vector<float> > > allData;
1866 std::map<std::string, int > allDataOi;
1868 for(
int i=0; i<
ids_.size(); ++i)
1871 std::map<std::string, float> statistics;
1872 if(allStats.find(
ids_[i]) != allStats.end())
1874 statistics = allStats.at(
ids_[i]).first;
1875 stamp = allStats.at(
ids_[i]).second;
1881 for(std::map<std::string, float>::iterator iter=statistics.begin(); iter!=statistics.end(); ++iter)
1883 if(allData.find(iter->first) == allData.end())
1886 allData.insert(std::make_pair(iter->first, std::make_pair(std::vector<float>(
ids_.size(), 0.0f), std::vector<float>(
ids_.size(), 0.0f) )));
1887 allDataOi.insert(std::make_pair(iter->first, 0));
1890 int & oi = allDataOi.at(iter->first);
1891 allData.at(iter->first).first[oi] =
ui_->checkBox_timeStats->isChecked()?float(stamp-firstStamp):
ids_[i];
1892 allData.at(iter->first).second[oi] = iter->second;
1897 for(std::map<std::string, std::pair<std::vector<float>, std::vector<float> > >::iterator iter=allData.begin(); iter!=allData.end(); ++iter)
1899 int oi = allDataOi.at(iter->first);
1900 iter->second.first.resize(oi);
1901 iter->second.second.resize(oi);
1902 ui_->toolBox_statistics->updateStat(iter->first.c_str(), iter->second.first, iter->second.second,
true);
1910 QColor c = QColorDialog::getColor(
ui_->lineEdit_obstacleColor->text(),
this);
1913 ui_->lineEdit_obstacleColor->setText(c.name());
1918 QColor c = QColorDialog::getColor(
ui_->lineEdit_groundColor->text(),
this);
1921 ui_->lineEdit_groundColor->setText(c.name());
1926 QColor c = QColorDialog::getColor(
ui_->lineEdit_emptyColor->text(),
this);
1929 ui_->lineEdit_emptyColor->setText(c.name());
1936 int id =
ids_.at(
ui_->horizontalSlider_A->value());
1986 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
1988 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No graph in database?!"));
1997 QMessageBox::warning(
this, tr(
"Cannot export poses"), tr(
"No GPS in database?!"));
2001 std::map<int, rtabmap::Transform> graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
2004 pcl::PointCloud<pcl::PointXYZ> cloud1, cloud2;
2005 cloud1.resize(graph.size());
2006 cloud2.resize(graph.size());
2009 for(std::map<int, Transform>::const_iterator iter=
gpsPoses_.begin(); iter!=
gpsPoses_.end(); ++iter)
2011 std::map<int, Transform>::iterator iter2 = graph.find(iter->first);
2012 if(iter2!=graph.end())
2016 idFirst = iter->first;
2018 cloud1[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
2019 cloud2[oi++] = pcl::PointXYZ(iter2->second.x(), iter2->second.y(), iter2->second.z());
2033 t =
gpsPoses_.at(idFirst) * graph.at(idFirst).inverse();
2036 std::map<int, GPS> values;
2038 for(std::map<int, Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
2040 iter->second = t * iter->second;
2043 coord.
fromENU_WGS84(cv::Point3d(iter->second.x(), iter->second.y(), iter->second.z()), origin);
2044 double bearing = -(iter->second.theta()*180.0/
M_PI-90.0);
2055 std::vector<float> v;
2061 QString output =
pathDatabase_ + QDir::separator() +
"poses.kml";
2062 QString path = QFileDialog::getSaveFileName(
2066 tr(
"Google Earth file (*.kml)"));
2070 bool saved =
graph::exportGPS(path.toStdString(), values,
ui_->graphViewer->getNodeColor().rgba());
2074 QMessageBox::information(
this,
2075 tr(
"Export poses..."),
2076 tr(
"GPS coordinates saved to \"%1\".")
2081 QMessageBox::information(
this,
2082 tr(
"Export poses..."),
2083 tr(
"Failed to save GPS coordinates to \"%1\"!")
2091 std::map<int, Transform> optimizedPoses;
2100 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked())
2103 if(refPoses.empty())
2111 float translational_rmse = 0.0f;
2112 float translational_mean = 0.0f;
2113 float translational_median = 0.0f;
2114 float translational_std = 0.0f;
2115 float translational_min = 0.0f;
2116 float translational_max = 0.0f;
2117 float rotational_rmse = 0.0f;
2118 float rotational_mean = 0.0f;
2119 float rotational_median = 0.0f;
2120 float rotational_std = 0.0f;
2121 float rotational_min = 0.0f;
2122 float rotational_max = 0.0f;
2129 translational_median,
2140 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked() && !gtToMap.
isIdentity())
2142 for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
2144 iter->second = gtToMap * iter->second;
2151 if(optimizedPoses.size())
2153 std::map<int, Transform> localTransforms;
2155 items.push_back(
"Robot");
2156 items.push_back(
"Camera");
2157 items.push_back(
"Scan");
2159 QString item = QInputDialog::getItem(
this, tr(
"Export Poses"), tr(
"Frame: "), items, 0,
false, &ok);
2160 if(!ok || item.isEmpty())
2164 if(item.compare(
"Robot") != 0)
2166 bool cameraFrame = item.compare(
"Camera") == 0;
2167 for(std::map<int, Transform>::iterator iter=optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter)
2172 std::vector<CameraModel> models;
2176 if((models.size() == 1 &&
2177 !models.at(0).localTransform().isNull()))
2179 localTransform = models.at(0).localTransform();
2185 else if(models.size()>1)
2187 UWARN(
"Multi-camera is not supported (node %d)", iter->first);
2191 UWARN(
"Calibration not valid for node %d", iter->first);
2196 UWARN(
"Missing calibration for node %d", iter->first);
2208 UWARN(
"Missing scan info for node %d", iter->first);
2212 if(!localTransform.
isNull())
2214 localTransforms.insert(std::make_pair(iter->first, localTransform));
2217 if(localTransforms.empty())
2219 QMessageBox::warning(
this,
2221 tr(
"Could not find any \"%1\" frame, exporting in Robot frame instead.").arg(item));
2225 std::map<int, Transform> poses;
2226 std::multimap<int, Link> links;
2227 if(localTransforms.empty())
2229 poses = optimizedPoses;
2235 for(std::map<int, Transform>::iterator iter=localTransforms.begin(); iter!=localTransforms.end(); ++iter)
2237 poses.insert(std::make_pair(iter->first, optimizedPoses.at(iter->first) * iter->second));
2243 std::multimap<int, Link>::iterator inserted = links.insert(*iter);
2244 int from = iter->second.from();
2245 int to = iter->second.to();
2246 inserted->second.setTransform(localTransforms.at(from).inverse()*iter->second.transform()*localTransforms.at(to));
2251 std::map<int, double> stamps;
2254 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
2261 std::vector<float> v;
2265 stamps.insert(std::make_pair(iter->first, stamp));
2268 if(stamps.size()!=poses.size())
2270 QMessageBox::warning(
this, tr(
"Export poses..."), tr(
"Poses (%1) and stamps (%2) have not the same size! Cannot export in RGB-D SLAM format.")
2271 .arg(poses.size()).arg(stamps.size()));
2276 QString output =
pathDatabase_ + QDir::separator() + (format==3?
"toro.graph":format==4?
"poses.g2o":
"poses.txt");
2278 QString path = QFileDialog::getSaveFileName(
2282 format == 3?tr(
"TORO file (*.graph)"):format==4?tr(
"g2o file (*.g2o)"):tr(
"Text file (*.txt)"));
2286 if(QFileInfo(path).suffix() ==
"")
2306 QMessageBox::information(
this,
2307 tr(
"Export poses..."),
2308 tr(
"%1 saved to \"%2\".")
2309 .arg(format == 3?
"TORO graph":format == 4?
"g2o graph":
"Poses")
2314 QMessageBox::information(
this,
2315 tr(
"Export poses..."),
2316 tr(
"Failed to save %1 to \"%2\"!")
2317 .arg(format == 3?
"TORO graph":format == 4?
"g2o graph":
"poses")
2337 QString output =
pathDatabase_ + QDir::separator() + (format==0?
"gps.txt":
"gps.kml");
2338 QString path = QFileDialog::getSaveFileName(
2342 format==0?tr(
"Raw format (*.txt)"):tr(
"Google Earth file (*.kml)"));
2350 QMessageBox::information(
this,
2351 tr(
"Export poses..."),
2352 tr(
"GPS coordinates saved to \"%1\".")
2357 QMessageBox::information(
this,
2358 tr(
"Export poses..."),
2359 tr(
"Failed to save GPS coordinates to \"%1\"!")
2370 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
2374 float xMin, yMin, cellSize;
2378 QMessageBox::warning(
this, tr(
"Cannot export 2D map"), tr(
"The database doesn't contain a saved 2D map."));
2384 QString path = QFileDialog::getSaveFileName(
2392 if(QFileInfo(path).suffix() ==
"")
2396 cv::imwrite(path.toStdString(), map8U);
2397 QMessageBox::information(
this, tr(
"Export 2D map"), tr(
"Exported %1!").arg(path));
2406 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"A database must must loaded first...\nUse File->Open database."));
2410 float xMin, yMin, cellSize;
2414 QMessageBox::warning(
this, tr(
"Cannot import 2D map"), tr(
"The database doesn't contain a saved 2D map."));
2418 QString path = QFileDialog::getOpenFileName(
2425 cv::Mat map8U = cv::imread(path.toStdString(), cv::IMREAD_UNCHANGED);
2428 if(mapOrg.cols == map.cols && mapOrg.rows == map8U.rows)
2431 QMessageBox::information(
this, tr(
"Import 2D map"), tr(
"Imported %1!").arg(path));
2435 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));
2445 QMessageBox::warning(
this, tr(
"Cannot view optimized mesh"), tr(
"A database must must loaded first...\nUse File->Open database."));
2449 std::vector<std::vector<std::vector<unsigned int> > > polygons;
2450 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 2451 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
2453 std::vector<std::vector<Eigen::Vector2f> > texCoords;
2457 if(cloudMat.empty())
2459 QMessageBox::warning(
this, tr(
"Cannot view optimized mesh"), tr(
"The database doesn't contain a saved optimized mesh."));
2464 viewer->setWindowFlags(Qt::Window);
2465 viewer->setAttribute(Qt::WA_DeleteOnClose);
2467 if(!textures.empty())
2471 viewer->setWindowTitle(
"Optimized Textured Mesh");
2475 else if(polygons.size() == 1)
2478 viewer->setWindowTitle(
"Optimized Mesh");
2486 viewer->setWindowTitle(
"Optimized Point Cloud");
2497 QMessageBox::warning(
this, tr(
"Cannot export optimized mesh"), tr(
"A database must must loaded first...\nUse File->Open database."));
2501 std::vector<std::vector<std::vector<unsigned int> > > polygons;
2502 #if PCL_VERSION_COMPARE(>=, 1, 8, 0) 2503 std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
2505 std::vector<std::vector<Eigen::Vector2f> > texCoords;
2509 if(cloudMat.empty())
2511 QMessageBox::warning(
this, tr(
"Cannot export optimized mesh"), tr(
"The database doesn't contain a saved optimized mesh."));
2517 if(!textures.empty())
2520 QString path = QFileDialog::getSaveFileName(
2524 tr(
"Mesh (*.obj)"));
2528 if(QFileInfo(path).suffix() ==
"")
2532 QString baseName = QFileInfo(path).baseName();
2533 if(mesh->tex_materials.size() == 1)
2535 mesh->tex_materials.at(0).tex_file = baseName.toStdString() +
".png";
2536 cv::imwrite((QFileInfo(path).absoluteDir().absolutePath()+QDir::separator()+baseName).toStdString() +
".png", textures);
2540 for(
unsigned int i=0; i<mesh->tex_materials.size(); ++i)
2542 mesh->tex_materials.at(i).tex_file = (baseName+QDir::separator()+QString::number(i)+
".png").toStdString();
2543 UASSERT((i+1)*textures.rows <= (
unsigned int)textures.cols);
2544 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)));
2547 pcl::io::saveOBJFile(path.toStdString(), *mesh);
2549 QMessageBox::information(
this, tr(
"Export Textured Mesh"), tr(
"Exported %1!").arg(path));
2552 else if(polygons.size() == 1)
2555 QString path = QFileDialog::getSaveFileName(
2559 tr(
"Mesh (*.ply)"));
2563 if(QFileInfo(path).suffix() ==
"")
2567 pcl::io::savePLYFileBinary(path.toStdString(), *mesh);
2568 QMessageBox::information(
this, tr(
"Export Mesh"), tr(
"Exported %1!").arg(path));
2573 QString path = QFileDialog::getSaveFileName(
2577 tr(
"Point cloud data (*.ply *.pcd)"));
2581 if(QFileInfo(path).suffix() ==
"")
2585 bool success =
false;
2587 if(QFileInfo(path).suffix() ==
"pcd")
2589 success = pcl::io::savePCDFile(path.toStdString(), *cloud) == 0;
2593 success = pcl::io::savePLYFile(path.toStdString(), *cloud) == 0;
2597 QMessageBox::information(
this, tr(
"Export Point Cloud"), tr(
"Exported %1!").arg(path));
2601 QMessageBox::critical(
this, tr(
"Export Point Cloud"), tr(
"Failed exporting %1!").arg(path));
2612 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
2619 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
2621 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
2626 std::map<int, Transform> optimizedPoses;
2635 if(
ui_->groupBox_posefiltering->isChecked())
2638 ui_->doubleSpinBox_posefilteringRadius->value(),
2639 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
2641 if(optimizedPoses.size() > 0)
2647 std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr> clouds;
2648 std::map<int, pcl::PolygonMesh::Ptr> meshes;
2649 std::map<int, pcl::TextureMesh::Ptr> textureMeshes;
2650 std::vector<std::map<int, pcl::PointXY> > textureVertexToPixels;
2656 QMap<int, Signature>(),
2657 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
2658 std::map<int, LaserScan>(),
2660 ui_->parameters_toolbox->getParameters(),
2664 textureVertexToPixels))
2666 if(textureMeshes.size())
2670 cv::Mat globalTextures;
2671 pcl::TextureMeshPtr textureMesh = textureMeshes.at(0);
2672 if(textureMesh->tex_materials.size()>1)
2676 std::map<int, cv::Mat>(),
2677 std::map<
int, std::vector<CameraModel> >(),
2682 textureVertexToPixels,
2695 textureMesh->tex_coordinates,
2697 QMessageBox::information(
this, tr(
"Update Optimized Textured Mesh"), tr(
"Updated!"));
2698 ui_->actionView_optimized_mesh->setEnabled(
true);
2699 ui_->actionExport_optimized_mesh->setEnabled(
true);
2702 else if(meshes.size())
2705 std::vector<std::vector<std::vector<unsigned int> > > polygons(1);
2708 QMessageBox::information(
this, tr(
"Update Optimized Mesh"), tr(
"Updated!"));
2709 ui_->actionView_optimized_mesh->setEnabled(
true);
2710 ui_->actionExport_optimized_mesh->setEnabled(
true);
2713 else if(clouds.size())
2717 QMessageBox::information(
this, tr(
"Update Optimized PointCloud"), tr(
"Updated!"));
2718 ui_->actionView_optimized_mesh->setEnabled(
true);
2719 ui_->actionExport_optimized_mesh->setEnabled(
true);
2724 QMessageBox::critical(
this, tr(
"Update Optimized Mesh"), tr(
"Nothing to save!"));
2731 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
2739 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"A database must must loaded first...\nUse File->Open database."));
2743 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save File"),
pathDatabase_+
"/Graph.dot", tr(
"Graphiz file (*.dot)"));
2754 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
2758 int id = QInputDialog::getInt(
this, tr(
"Around which location?"), tr(
"Location ID"),
ids_.first(),
ids_.first(),
ids_.last(), 1, &ok);
2762 int margin = QInputDialog::getInt(
this, tr(
"Depth around the location?"), tr(
"Margin"), 4, 1, 100, 1, &ok);
2765 QString path = QFileDialog::getSaveFileName(
this, tr(
"Save File"),
pathDatabase_+
"/Graph" + QString::number(
id) +
".dot", tr(
"Graphiz file (*.dot)"));
2766 if(!path.isEmpty() &&
id>0)
2768 std::map<int, int> ids;
2769 std::list<int> curentMarginList;
2770 std::set<int> currentMargin;
2771 std::set<int> nextMargin;
2772 nextMargin.insert(
id);
2774 while((margin == 0 || m < margin) && nextMargin.size())
2776 curentMarginList = std::list<int>(nextMargin.rbegin(), nextMargin.rend());
2779 for(std::list<int>::iterator jter = curentMarginList.begin(); jter!=curentMarginList.end(); ++jter)
2781 if(ids.find(*jter) == ids.end())
2783 std::map<int, Link> links;
2784 ids.insert(std::pair<int, int>(*jter, m));
2790 for(std::map<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
2798 nextMargin.insert(iter->first);
2803 if(currentMargin.insert(iter->first).second)
2805 curentMarginList.push_back(iter->first);
2817 ids.insert(std::pair<int,int>(
id, 0));
2818 std::set<int> idsSet;
2819 for(std::map<int, int>::iterator iter = ids.begin(); iter!=ids.end(); ++iter)
2821 idsSet.insert(idsSet.end(), iter->first);
2822 UINFO(
"Node %d", iter->first);
2824 UINFO(
"idsSet=%d", idsSet.size());
2829 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for signature %1.").arg(
id));
2845 progressDialog.show();
2849 plot->setWindowFlags(Qt::Window);
2850 plot->setWindowTitle(
"Local Occupancy Grid Generation Time (ms)");
2851 plot->setAttribute(Qt::WA_DeleteOnClose);
2857 plotCells->setWindowFlags(Qt::Window);
2858 plotCells->setWindowTitle(
"Occupancy Cells");
2859 plotCells->setAttribute(Qt::WA_DeleteOnClose);
2866 double decompressionTime = 0;
2867 double gridCreationTime = 0;
2869 for(
int i =0; i<
ids_.size() && !progressDialog.
isCanceled(); ++i)
2875 decompressionTime = timer.
ticks()*1000.0;
2882 std::vector<float> velocity;
2888 cv::Mat ground, obstacles, empty;
2889 cv::Point3f viewpoint;
2909 viewpoint.x += t.
x();
2910 viewpoint.y += t.
y();
2911 viewpoint.z += t.
z();
2925 viewpoint = cv::Point3f(t.
x(), t.
y(), t.
z());
2933 grid.createLocalMap(s, ground, obstacles, empty, viewpoint);
2936 gridCreationTime = timer.
ticks()*1000.0;
2939 msg = QString(
"Generated local occupancy grid map %1/%2").arg(i+1).arg((
int)
ids_.size());
2941 totalCurve->
addValue(
ids_.at(i), obstacles.cols+ground.cols+empty.cols);
2950 decompressionCurve->
addValue(
ids_.at(i), decompressionTime);
2951 gridCreationCurve->
addValue(
ids_.at(i), gridCreationTime);
2953 if(
ids_.size() < 50 || (i+1) % 25 == 0)
2955 QApplication::processEvents();
2976 if(
ids_.size() == 0)
2978 UWARN(
"ids_ is empty!");
2983 idsSet.insert(
ids_.at(
ui_->horizontalSlider_A->value()));
2984 idsSet.insert(
ids_.at(
ui_->horizontalSlider_B->value()));
2985 QList<int> ids = idsSet.toList();
2989 progressDialog.show();
2991 for(
int i =0; i<ids.size(); ++i)
3005 std::vector<float> velocity;
3011 cv::Mat ground, obstacles, empty;
3012 cv::Point3f viewpoint;
3031 viewpoint.x += t.
x();
3032 viewpoint.y += t.
y();
3033 viewpoint.z += t.
z();
3047 viewpoint = cv::Point3f(t.
x(), t.
y(), t.
z());
3055 grid.createLocalMap(s, ground, obstacles, empty, viewpoint);
3061 msg = QString(
"Generated local occupancy grid map %1/%2 (%3s)").arg(i+1).arg((
int)ids.size()).arg(time.
ticks());
3066 QApplication::processEvents();
3085 QMessageBox::warning(
this, tr(
"Cannot view 3D map"), tr(
"The database is empty..."));
3092 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3094 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3099 std::map<int, Transform> optimizedPoses;
3108 if(
ui_->groupBox_posefiltering->isChecked())
3111 ui_->doubleSpinBox_posefilteringRadius->value(),
3112 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
3114 if(optimizedPoses.size() > 0)
3120 QMap<int, Signature>(),
3121 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
3122 std::map<int, LaserScan>(),
3124 ui_->parameters_toolbox->getParameters());
3128 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
3136 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"The database is empty..."));
3143 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3145 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3150 std::map<int, Transform> optimizedPoses;
3159 if(
ui_->groupBox_posefiltering->isChecked())
3162 ui_->doubleSpinBox_posefilteringRadius->value(),
3163 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
3165 if(optimizedPoses.size() > 0)
3171 QMap<int, Signature>(),
3172 std::map<
int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
3173 std::map<int, LaserScan>(),
3175 ui_->parameters_toolbox->getParameters());
3179 QMessageBox::critical(
this, tr(
"Error"), tr(
"No neighbors found for node %1.").arg(
ui_->spinBox_optimizationsFrom->value()));
3188 if(
graphes_.empty() ||
ui_->horizontalSlider_iterations->maximum() != (int)
graphes_.size()-1)
3190 QMessageBox::warning(
this, tr(
"Cannot generate a graph"), tr(
"No graph in database?!"));
3195 const std::map<int, Transform> & optimizedPoses =
graphes_.back();
3198 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
3201 progressDialog->setMinimumWidth(800);
3202 progressDialog->show();
3204 int iterations =
ui_->spinBox_detectMore_iterations->value();
3207 std::multimap<int, int> checkedLoopClosures;
3208 std::pair<int, int> lastAdded(0,0);
3209 for(
int n=0; n<iterations; ++n)
3211 UINFO(
"iteration %d/%d", n+1, iterations);
3214 ui_->doubleSpinBox_detectMore_radius->value(),
3215 ui_->doubleSpinBox_detectMore_angle->value()*CV_PI/180.0);
3218 progressDialog->
appendText(tr(
"Looking for more loop closures, clusters found %1 clusters.").arg(clusters.size()));
3219 QApplication::processEvents();
3225 std::set<int> addedLinks;
3227 for(std::multimap<int, int>::iterator iter=clusters.begin(); iter!= clusters.end() && !progressDialog->
isCanceled(); ++iter, ++i)
3229 int from = iter->first;
3230 int to = iter->second;
3233 from = iter->second;
3241 addedLinks.find(from) == addedLinks.end() && addedLinks.find(to) == addedLinks.end())
3243 checkedLoopClosures.insert(std::make_pair(from, to));
3246 UINFO(
"Added new loop closure between %d and %d.", from, to);
3248 addedLinks.insert(from);
3249 addedLinks.insert(to);
3250 lastAdded.first = from;
3251 lastAdded.second = to;
3253 progressDialog->
appendText(tr(
"Detected loop closure %1->%2! (%3/%4)").arg(from).arg(to).arg(i+1).arg(clusters.size()));
3254 QApplication::processEvents();
3261 QApplication::processEvents();
3264 UINFO(
"Iteration %d/%d: added %d loop closures.", n+1, iterations, (
int)addedLinks.size()/2);
3265 progressDialog->
appendText(tr(
"Iteration %1/%2: Detected %3 loop closures!").arg(n+1).arg(iterations).arg(addedLinks.size()/2));
3266 if(addedLinks.size() == 0)
3277 UINFO(
"Total added %d loop closures.", added);
3279 progressDialog->
appendText(tr(
"Total new loop closures detected=%1").arg(added));
3288 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
3291 progressDialog->setMinimumWidth(800);
3292 progressDialog->show();
3300 progressDialog->
appendText(tr(
"Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(
neighborLinks_.size()));
3302 QApplication::processEvents();
3311 progressDialog->
appendText(
"Refining links finished!");
3320 progressDialog->setAttribute(Qt::WA_DeleteOnClose);
3323 progressDialog->setMinimumWidth(800);
3324 progressDialog->show();
3332 progressDialog->
appendText(tr(
"Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(
loopLinks_.size()));
3334 QApplication::processEvents();
3343 progressDialog->
appendText(
"Refining links finished!");
3362 ui_->label_parentsA,
3363 ui_->label_childrenA,
3367 ui_->graphicsView_A,
3381 ui_->label_parentsB,
3382 ui_->label_childrenB,
3386 ui_->graphicsView_B,
3397 QLabel * labelIndex,
3398 QLabel * labelParents,
3399 QLabel * labelChildren,
3405 QLabel * labelMapId,
3407 QLabel * labelVelocity,
3408 QLabel * labelCalib,
3413 labelIndex->setText(QString::number(value));
3414 labelParents->clear();
3415 labelChildren->clear();
3418 labelMapId->clear();
3420 labelVelocity->clear();
3422 labelCalib->clear();
3425 if(value >= 0 && value <
ids_.size())
3428 int id =
ids_.at(value);
3430 labelId->setText(QString::number(
id));
3450 if(
ui_->spinBox_mesh_fillDepthHoles->value() > 0)
3460 std::list<Signature*> signatures;
3463 if(signatures.size() && signatures.front()!=0 && signatures.front()->getWords().size())
3472 std::vector<float> v;
3477 label->setText(l.c_str());
3480 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));
3483 stamp->setText(QString::number(s,
'f'));
3484 stamp->setToolTip(QDateTime::fromMSecsSinceEpoch(s*1000.0).toString(
"dd.MM.yyyy hh:mm:ss.zzz"));
3488 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]));
3492 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()));
3493 labelGps->setToolTip(QDateTime::fromMSecsSinceEpoch(gps.
stamp()*1000.0).toString(
"dd.MM.yyyy hh:mm:ss.zzz"));
3501 labelCalib->setText(tr(
"%1 %2x%3 [%8x%9] fx=%4 fy=%5 cx=%6 cy=%7 T=%10")
3511 .arg(data.
cameraModels()[0].localTransform().prettyPrint().c_str()));
3515 labelCalib->setText(tr(
"%1 %2x%3 fx=%4 fy=%5 cx=%6 cy=%7 T=%8")
3523 .arg(data.
cameraModels()[0].localTransform().prettyPrint().c_str()));
3529 labelCalib->setText(tr(
"%1x%2 fx=%3 fy=%4 cx=%5 cy=%6 baseline=%7m T=%8")
3543 labelCalib->setText(
"NA");
3554 ui_->graphicsView_stereo->clear();
3561 if(signatures.size() &&
ui_->checkBox_odomFrame_3dview->isChecked())
3564 (*signatures.begin())->getPose().getTranslationAndEulerAngles(x, y, z, roll, pitch, yaw);
3578 if(
ui_->checkBox_showCloud->isChecked() ||
ui_->checkBox_showMesh->isChecked())
3584 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
3585 pcl::IndicesPtr indices(
new std::vector<int>);
3589 if(
ui_->spinBox_mesh_fillDepthHoles->value() > 0)
3597 ui_->spinBox_decimation->value(),0,0,indices.get());
3610 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
3615 if(
ui_->checkBox_showMesh->isChecked() && !cloud->is_dense)
3617 Eigen::Vector3f viewpoint(0.0
f,0.0
f,0.0
f);
3620 viewpoint[0] = data.
cameraModels()[0].localTransform().x();
3621 viewpoint[1] = data.
cameraModels()[0].localTransform().y();
3622 viewpoint[2] = data.
cameraModels()[0].localTransform().z();
3632 float(
ui_->spinBox_mesh_angleTolerance->value())*
M_PI/180.0
f,
3633 ui_->checkBox_mesh_quad->isChecked(),
3634 ui_->spinBox_mesh_triangleSize->value(),
3637 if(
ui_->spinBox_mesh_minClusterSize->value())
3640 std::vector<std::set<int> > neighbors;
3641 std::vector<std::set<int> > vertexToPolygons;
3648 ui_->spinBox_mesh_minClusterSize->value());
3649 std::vector<pcl::Vertices> filteredPolygons(polygons.size());
3651 for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
3653 for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
3655 filteredPolygons[oi++] = polygons.at(*jter);
3658 filteredPolygons.resize(oi);
3659 polygons = filteredPolygons;
3664 if(
ui_->checkBox_showCloud->isChecked())
3670 else if(
ui_->checkBox_showCloud->isChecked())
3672 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
3673 pcl::IndicesPtr indices(
new std::vector<int>);
3677 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
3702 if(
ui_->checkBox_showWords->isChecked() && signatures.size())
3704 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
3705 cloud->resize((*signatures.begin())->getWords3().size());
3707 for(std::multimap<int, cv::Point3f>::const_iterator iter=(*signatures.begin())->getWords3().begin();
3708 iter!=(*signatures.begin())->getWords3().end();
3711 cloud->at(i++) = pcl::PointXYZ(iter->second.x, iter->second.y, iter->second.z);
3756 if(
ui_->checkBox_showMap->isChecked() ||
ui_->checkBox_showGrid->isChecked())
3758 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> > localMaps;
3759 std::map<int, std::pair<float, cv::Point3f> > localMapsInfo;
3770 if(!localMaps.empty())
3772 std::map<int, Transform> poses;
3773 poses.insert(std::make_pair(data.
id(), pose));
3775 #ifdef RTABMAP_OCTOMAP 3777 if(
ui_->checkBox_octomap->isChecked() &&
3778 (!localMaps.begin()->second.first.first.empty() || !localMaps.begin()->second.first.second.empty()) &&
3779 (localMaps.begin()->second.first.first.empty() || localMaps.begin()->second.first.first.channels() > 2) &&
3780 (localMaps.begin()->second.first.second.empty() || localMaps.begin()->second.first.second.channels() > 2) &&
3781 (localMaps.begin()->second.second.empty() || localMaps.begin()->second.second.channels() > 2) &&
3782 localMapsInfo.begin()->second.first > 0.0f)
3785 octomap =
new OctoMap(localMapsInfo.begin()->second.first);
3786 octomap->
addToCache(data.
id(), localMaps.begin()->second.first.first, localMaps.begin()->second.first.second, localMaps.begin()->second.second, localMapsInfo.begin()->second.second);
3791 if(
ui_->checkBox_showMap->isChecked())
3793 float xMin=0.0f, yMin=0.0f;
3796 float gridCellSize = Parameters::defaultGridCellSize();
3798 #ifdef RTABMAP_OCTOMAP 3808 grid.addToCache(data.
id(), localMaps.begin()->second.first.first, localMaps.begin()->second.first.second, localMaps.begin()->second.second);
3810 map8S = grid.getMap(xMin, yMin);
3819 if(
ui_->checkBox_showGrid->isChecked())
3821 #ifdef RTABMAP_OCTOMAP 3824 if(
ui_->comboBox_octomap_rendering_type->currentIndex()== 0)
3826 pcl::IndicesPtr obstacles(
new std::vector<int>);
3827 pcl::IndicesPtr empty(
new std::vector<int>);
3828 pcl::IndicesPtr ground(
new std::vector<int>);
3829 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap->
createCloud(
ui_->spinBox_grid_depth->value(), obstacles.get(), empty.get(), ground.get());
3832 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3833 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
3837 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
3838 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
3844 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZ>);
3845 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
3849 pcl::PointCloud<pcl::PointXYZ>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZ>);
3850 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
3855 if(
ui_->checkBox_grid_empty->isChecked())
3857 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZ>);
3858 pcl::copyPointCloud(*cloud, *empty, *emptyCloud);
3895 if(
ui_->checkBox_grid_empty->isChecked())
3900 QColor(
ui_->lineEdit_emptyColor->text()));
3906 #ifdef RTABMAP_OCTOMAP 3917 if(signatures.size())
3919 UASSERT(signatures.front() != 0 && signatures.size() == 1);
3920 delete signatures.front();
3935 if(!imgDepth.empty())
3940 rect.setWidth(imgDepth.cols);
3941 rect.setHeight(imgDepth.rows);
3950 std::map<int, rtabmap::Link> links;
3954 QString strParents, strChildren;
3955 for(std::map<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
3960 if(iter->first <
id)
3962 strChildren.append(QString(
"%1 ").arg(iter->first));
3966 strParents.append(QString(
"%1 ").arg(iter->first));
3970 labelParents->setText(strParents);
3971 labelChildren->setText(strChildren);
3977 labelMapId->setText(QString::number(mapId));
3988 if(updateConstraintView &&
ui_->dockWidget_constraints->isVisible())
3991 int from =
ids_.at(
ui_->horizontalSlider_A->value());
3992 int to =
ids_.at(
ui_->horizontalSlider_B->value());
4001 if(i !=
ui_->horizontalSlider_loops->value())
4003 ui_->horizontalSlider_loops->blockSignals(
true);
4004 ui_->horizontalSlider_loops->setValue(i);
4005 ui_->horizontalSlider_loops->blockSignals(
false);
4008 ui_->horizontalSlider_neighbors->blockSignals(
true);
4009 ui_->horizontalSlider_neighbors->setValue(0);
4010 ui_->horizontalSlider_neighbors->blockSignals(
false);
4020 if(i !=
ui_->horizontalSlider_neighbors->value())
4022 ui_->horizontalSlider_neighbors->blockSignals(
true);
4023 ui_->horizontalSlider_neighbors->setValue(i);
4024 ui_->horizontalSlider_neighbors->blockSignals(
false);
4027 ui_->horizontalSlider_loops->blockSignals(
true);
4028 ui_->horizontalSlider_loops->setValue(0);
4029 ui_->horizontalSlider_loops->blockSignals(
false);
4037 ui_->horizontalSlider_loops->blockSignals(
true);
4038 ui_->horizontalSlider_neighbors->blockSignals(
true);
4039 ui_->horizontalSlider_loops->setValue(0);
4040 ui_->horizontalSlider_neighbors->setValue(0);
4041 ui_->horizontalSlider_loops->blockSignals(
false);
4042 ui_->horizontalSlider_neighbors->blockSignals(
false);
4049 std::map<int, Transform> optimizedPoses =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
4050 if(optimizedPoses.size() > 0)
4052 std::map<int, Transform>::iterator fromIter = optimizedPoses.find(from);
4053 std::map<int, Transform>::iterator toIter = optimizedPoses.find(to);
4054 if(fromIter != optimizedPoses.end() &&
4055 toIter != optimizedPoses.end())
4057 Link link(from, to,
Link::kUndef, fromIter->second.inverse() * toIter->second);
4076 if(this->parent() == 0)
4084 if(
ui_->horizontalSlider_A->maximum())
4086 int id =
ids_.at(
ui_->horizontalSlider_A->value());
4097 ui_->dockWidget_stereoView->isVisible() &&
4104 if(data->
imageRaw().channels() == 3)
4106 cv::cvtColor(data->
imageRaw(), leftMono, CV_BGR2GRAY);
4118 std::vector<cv::KeyPoint> kpts;
4119 uInsert(parameters,
ParametersPair(Parameters::kKpMaxFeatures(), parameters.at(Parameters::kVisMaxFeatures())));
4120 uInsert(parameters,
ParametersPair(Parameters::kKpMinDepth(), parameters.at(Parameters::kVisMinDepth())));
4121 uInsert(parameters,
ParametersPair(Parameters::kKpMaxDepth(), parameters.at(Parameters::kVisMaxDepth())));
4122 uInsert(parameters,
ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kVisFeatureType())));
4123 uInsert(parameters,
ParametersPair(Parameters::kKpRoiRatios(), parameters.at(Parameters::kVisRoiRatios())));
4124 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixEps(), parameters.at(Parameters::kVisSubPixEps())));
4125 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixIterations(), parameters.at(Parameters::kVisSubPixIterations())));
4126 uInsert(parameters,
ParametersPair(Parameters::kKpSubPixWinSize(), parameters.at(Parameters::kVisSubPixWinSize())));
4131 float timeKpt = timer.
ticks();
4133 std::vector<cv::Point2f> leftCorners;
4134 cv::KeyPoint::convert(kpts, leftCorners);
4137 std::vector<unsigned char> status;
4138 std::vector<cv::Point2f> rightCorners;
4147 float timeStereo = timer.
ticks();
4149 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
4150 cloud->resize(kpts.size());
4151 float bad_point = std::numeric_limits<float>::quiet_NaN ();
4152 UASSERT(status.size() == kpts.size());
4155 int flowOutliers= 0;
4156 int slopeOutliers= 0;
4157 int negativeDisparityOutliers = 0;
4158 for(
unsigned int i=0; i<status.size(); ++i)
4160 cv::Point3f pt(bad_point, bad_point, bad_point);
4163 float disparity = leftCorners[i].x - rightCorners[i].x;
4164 if(disparity > 0.0
f)
4176 cloud->at(oi++) = pcl::PointXYZ(pt.x, pt.y, pt.z);
4182 ++negativeDisparityOutliers;
4192 UINFO(
"correspondences = %d/%d (%f) (time kpt=%fs stereo=%fs)",
4193 (
int)cloud->size(), (int)leftCorners.size(), float(cloud->size())/
float(leftCorners.size()), timeKpt, timeStereo);
4199 ui_->label_stereo_inliers->setNum(inliers);
4200 ui_->label_stereo_flowOutliers->setNum(flowOutliers);
4201 ui_->label_stereo_slopeOutliers->setNum(slopeOutliers);
4202 ui_->label_stereo_disparityOutliers->setNum(negativeDisparityOutliers);
4204 std::vector<cv::KeyPoint> rightKpts;
4205 cv::KeyPoint::convert(rightCorners, rightKpts);
4206 std::vector<cv::DMatch> good_matches(kpts.size());
4207 for(
unsigned int i=0; i<good_matches.size(); ++i)
4209 good_matches[i].trainIdx = i;
4210 good_matches[i].queryIdx = i;
4222 ui_->graphicsView_stereo->clear();
4223 ui_->graphicsView_stereo->setLinesShown(
true);
4224 ui_->graphicsView_stereo->setFeaturesShown(
false);
4225 ui_->graphicsView_stereo->setImageDepthShown(
true);
4231 for(
unsigned int i=0; i<kpts.size(); ++i)
4233 if(rightKpts[i].pt.x > 0 && rightKpts[i].pt.y > 0)
4235 QColor c = Qt::green;
4240 else if(status[i] == 100)
4244 else if(status[i] == 101)
4248 else if(status[i] == 102)
4252 else if(status[i] == 110)
4256 ui_->graphicsView_stereo->addLine(
4262 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));
4265 ui_->graphicsView_stereo->update();
4271 int from =
ids_.at(
ui_->horizontalSlider_A->value());
4272 int to =
ids_.at(
ui_->horizontalSlider_B->value());
4276 ui_->graphicsView_A->clearLines();
4277 ui_->graphicsView_A->setFeaturesColor(QColor(255, 255, 0, alpha));
4278 ui_->graphicsView_B->clearLines();
4279 ui_->graphicsView_B->setFeaturesColor(QColor(255, 255, 0, alpha));
4281 const QMultiMap<int, KeypointItem*> & wordsA =
ui_->graphicsView_A->getFeatures();
4282 const QMultiMap<int, KeypointItem*> & wordsB =
ui_->graphicsView_B->getFeatures();
4283 if(wordsA.size() && wordsB.size())
4285 QList<int> ids = wordsA.uniqueKeys();
4286 for(
int i=0; i<ids.size(); ++i)
4288 if(ids[i] > 0 && wordsA.count(ids[i]) == 1 && wordsB.count(ids[i]) == 1)
4291 ui_->graphicsView_A->setFeatureColor(ids[i], Qt::magenta);
4292 ui_->graphicsView_B->setFeatureColor(ids[i], Qt::magenta);
4296 float scaleX =
ui_->graphicsView_A->viewScale();
4300 if(
ui_->actionVertical_Layout->isChecked())
4302 deltaY =
ui_->graphicsView_A->height()/scaleX;
4306 deltaX =
ui_->graphicsView_A->width()/scaleX;
4311 ui_->graphicsView_A->addLine(
4312 kptA->rect().x()+kptA->rect().width()/2,
4313 kptA->rect().y()+kptA->rect().height()/2,
4314 kptB->rect().x()+kptB->rect().width()/2+deltaX,
4315 kptB->rect().y()+kptB->rect().height()/2+deltaY,
4318 ui_->graphicsView_B->addLine(
4319 kptA->rect().x()+kptA->rect().width()/2-deltaX,
4320 kptA->rect().y()+kptA->rect().height()/2-deltaY,
4321 kptB->rect().x()+kptB->rect().width()/2,
4322 kptB->rect().y()+kptB->rect().height()/2,
4326 ui_->graphicsView_A->update();
4327 ui_->graphicsView_B->update();
4334 ui_->label_indexA->setText(QString::number(value));
4335 if(value>=0 && value <
ids_.size())
4337 ui_->label_idA->setText(QString::number(
ids_.at(value)));
4347 ui_->label_indexB->setText(QString::number(value));
4348 if(value>=0 && value <
ids_.size())
4350 ui_->label_idB->setText(QString::number(
ids_.at(value)));
4360 if(
ui_->dockWidget_view3d->isVisible())
4406 bool updateImageSliders,
4415 link = iterLink->second;
4417 else if(
ui_->checkBox_ignorePoseCorrection->isChecked())
4424 if(!poseFrom.
isNull() && !poseTo.isNull())
4428 link =
Link(link.from(),
4437 ui_->label_constraint->clear();
4438 ui_->label_constraint_opt->clear();
4439 ui_->checkBox_showOptimized->setEnabled(
false);
4442 ui_->label_type->setText(tr(
"%1 (%2)")
4451 ui_->label_variance->setText(QString(
"%1, %2")
4452 .arg(
sqrt(link.transVariance()))
4453 .arg(
sqrt(link.rotVariance())));
4454 std::stringstream out;
4455 out << link.infMatrix().inv();
4456 ui_->lineEdit_covariance->setText(out.str().c_str());
4457 ui_->label_constraint->setText(QString(
"%1").arg(t.prettyPrint().c_str()).replace(
" ",
"\n"));
4459 (int)
graphes_.size()-1 ==
ui_->horizontalSlider_iterations->maximum())
4461 std::map<int, rtabmap::Transform> & graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
4463 std::map<int, rtabmap::Transform>::iterator iterFrom = graph.find(link.from());
4464 std::map<int, rtabmap::Transform>::iterator iterTo = graph.find(link.to());
4465 if(iterFrom != graph.end() && iterTo != graph.end())
4467 ui_->checkBox_showOptimized->setEnabled(
true);
4472 float a = pcl::getAngle3D(Eigen::Vector4f(v1.
x(), v1.
y(), v1.
z(), 0), Eigen::Vector4f(v2.
x(), v2.
y(), v2.
z(), 0));
4473 a = (a *180.0f) / CV_PI;
4474 ui_->label_constraint_opt->setText(QString(
"%1\n(error=%2% a=%3)").arg(QString(topt.
prettyPrint().c_str()).replace(
" ",
"\n")).arg((diff/t.getNorm())*100.0
f).arg(a));
4476 if(
ui_->checkBox_showOptimized->isChecked())
4483 if(updateImageSliders)
4485 ui_->horizontalSlider_A->blockSignals(
true);
4486 ui_->horizontalSlider_B->blockSignals(
true);
4488 ui_->horizontalSlider_A->setValue(
idToIndex_.value(link.from()));
4489 ui_->horizontalSlider_B->setValue(
idToIndex_.value(link.to()));
4490 ui_->horizontalSlider_A->blockSignals(
false);
4491 ui_->horizontalSlider_B->blockSignals(
false);
4494 ui_->label_parentsA,
4495 ui_->label_childrenA,
4499 ui_->graphicsView_A,
4509 ui_->label_parentsB,
4510 ui_->label_childrenB,
4514 ui_->graphicsView_B,
4528 if(signatureFrom.
id()>0)
4540 if(signatureTo.
id()>0)
4554 if(
ui_->checkBox_odomFrame->isChecked())
4560 std::vector<float> v;
4575 if(
ui_->checkBox_show3Dclouds->isChecked())
4577 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFrom, cloudTo;
4578 pcl::IndicesPtr indicesFrom(
new std::vector<int>);
4579 pcl::IndicesPtr indicesTo(
new std::vector<int>);
4589 if(cloudTo.get() && indicesTo->size())
4595 if(
ui_->doubleSpinBox_gainCompensationRadius->value()>0.0 &&
4596 cloudFrom.get() && indicesFrom->size() &&
4597 cloudTo.get() && indicesTo->size())
4602 compensator.apply(0, cloudFrom, indicesFrom);
4603 compensator.apply(1, cloudTo, indicesTo);
4604 UINFO(
"Gain compensation time = %fs", t.
ticks());
4607 if(cloudFrom.get() && indicesFrom->size())
4609 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
4611 cloudFrom =
util3d::voxelize(cloudFrom, indicesFrom,
ui_->doubleSpinBox_voxelSize->value());
4615 if(cloudTo.get() && indicesTo->size())
4617 if(
ui_->doubleSpinBox_voxelSize->value() > 0.0)
4627 if(
ui_->checkBox_show3DWords->isChecked())
4630 ids.push_back(link.from());
4631 ids.push_back(link.to());
4632 std::list<Signature*> signatures;
4634 if(signatures.size() == 2)
4636 const Signature * sFrom = signatureFrom.
id()>0?&signatureFrom:signatures.front();
4637 const Signature * sTo = signatureTo.
id()>0?&signatureTo:signatures.back();
4639 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFrom(
new pcl::PointCloud<pcl::PointXYZ>);
4640 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTo(
new pcl::PointCloud<pcl::PointXYZ>);
4641 cloudFrom->resize(sFrom->
getWords3().size());
4642 cloudTo->resize(sTo->
getWords3().size());
4644 for(std::multimap<int, cv::Point3f>::const_iterator iter=sFrom->
getWords3().begin();
4648 cloudFrom->at(i++) = pcl::PointXYZ(iter->second.x, iter->second.y, iter->second.z);
4651 for(std::multimap<int, cv::Point3f>::const_iterator iter=sTo->
getWords3().begin();
4655 cloudTo->at(i++) = pcl::PointXYZ(iter->second.x, iter->second.y, iter->second.z);
4658 if(cloudFrom->size())
4671 if(cloudFrom->size())
4677 UWARN(
"Empty 3D words for node %d", link.from());
4686 UWARN(
"Empty 3D words for node %d", link.to());
4692 UERROR(
"Not found signature %d or %d in RAM", link.from(), link.to());
4697 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
4708 if(
ui_->checkBox_show2DScans->isChecked())
4712 !link.userDataCompressed().empty())
4714 std::vector<int> ids;
4715 cv::Mat userData = link.uncompressUserDataConst();
4716 if(userData.type() == CV_8SC1 &&
4717 userData.rows == 1 &&
4718 userData.cols >= 8 &&
4719 userData.at<
char>(userData.cols-1) == 0 &&
4720 memcmp(userData.data,
"SCANS:", 6) == 0)
4722 std::string scansStr = (
const char *)userData.data;
4723 UINFO(
"Detected \"%s\" in links's user data", scansStr.c_str());
4724 if(!scansStr.empty())
4726 std::list<std::string> strs =
uSplit(scansStr,
':');
4727 if(strs.size() == 2)
4729 std::list<std::string> strIds =
uSplit(strs.rbegin()->c_str(),
';');
4730 for(std::list<std::string>::iterator iter=strIds.begin(); iter!=strIds.end(); ++iter)
4732 ids.push_back(atoi(iter->c_str()));
4733 if(ids.back() == link.from())
4746 std::map<int, rtabmap::Transform> poses;
4747 for(
unsigned int i=0; i<ids.size(); ++i)
4755 UERROR(
"Not found %d node!", ids[i]);
4763 std::map<int, rtabmap::Transform> posesOut;
4764 std::multimap<int, rtabmap::Link> linksOut;
4772 if(poses.size() != posesOut.size())
4774 UWARN(
"Scan poses input and output are different! %d vs %d", (
int)poses.size(), (int)posesOut.size());
4775 UWARN(
"Input poses: ");
4776 for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
4778 UWARN(
" %d", iter->first);
4780 UWARN(
"Input links: ");
4782 for(std::multimap<int, Link>::iterator iter=modifiedLinks.begin(); iter!=modifiedLinks.end(); ++iter)
4784 UWARN(
" %d->%d", iter->second.from(), iter->second.to());
4790 std::map<int, rtabmap::Transform> finalPoses = optimizer->
optimize(link.to(), posesOut, linksOut);
4795 pcl::PointCloud<pcl::PointXYZ>::Ptr assembledScans(
new pcl::PointCloud<pcl::PointXYZ>);
4796 pcl::PointCloud<pcl::PointNormal>::Ptr assembledNormalScans(
new pcl::PointCloud<pcl::PointNormal>);
4797 pcl::PointCloud<pcl::PointXYZ>::Ptr graph(
new pcl::PointCloud<pcl::PointXYZ>);
4798 for(std::map<int, Transform>::iterator iter=finalPoses.begin(); iter!=finalPoses.end(); ++iter)
4800 iter->second = u * iter->second;
4801 if(iter->first != link.to())
4820 graph->push_back(pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z()));
4823 if(assembledNormalScans->size())
4828 if(assembledScans->size())
4848 pcl::PointCloud<pcl::PointNormal>::Ptr scan;
4855 pcl::PointCloud<pcl::PointXYZ>::Ptr scan;
4865 pcl::PointCloud<pcl::PointNormal>::Ptr scan;
4872 pcl::PointCloud<pcl::PointXYZ>::Ptr scan;
4882 #if PCL_VERSION_COMPARE(>=, 1, 7, 2) 4903 ui_->pushButton_refine->setEnabled(
false);
4904 ui_->pushButton_reset->setEnabled(
false);
4905 ui_->pushButton_add->setEnabled(
false);
4906 ui_->pushButton_reject->setEnabled(
false);
4908 int from =
ids_.at(
ui_->horizontalSlider_A->value());
4909 int to =
ids_.at(
ui_->horizontalSlider_B->value());
4915 ui_->pushButton_add->setEnabled(
true);
4922 ((currentLink.
from() == from && currentLink.
to() == to) || (currentLink.
from() == to && currentLink.
to() == from)))
4926 ui_->pushButton_reject->setEnabled(
4932 bool modified =
false;
4936 currentLink = iter->second;
4937 ui_->pushButton_reset->setEnabled(
true);
4942 ui_->pushButton_reset->setEnabled(
false);
4944 ui_->pushButton_refine->setEnabled(
true);
4955 if(refPoses.empty())
4965 if(refPoses.size() == graph.size() && length >= 100.0f)
4970 UINFO(
"KITTI t_err = %f %%", t_err);
4971 UINFO(
"KITTI r_err = %f deg/m", r_err);
4974 float translational_rmse = 0.0f;
4975 float translational_mean = 0.0f;
4976 float translational_median = 0.0f;
4977 float translational_std = 0.0f;
4978 float translational_min = 0.0f;
4979 float translational_max = 0.0f;
4980 float rotational_rmse = 0.0f;
4981 float rotational_mean = 0.0f;
4982 float rotational_median = 0.0f;
4983 float rotational_std = 0.0f;
4984 float rotational_min = 0.0f;
4985 float rotational_max = 0.0f;
4992 translational_median,
5004 ui_->label_rmse->setNum(translational_rmse);
5005 UINFO(
"translational_rmse=%f", translational_rmse);
5006 UINFO(
"translational_mean=%f", translational_mean);
5007 UINFO(
"translational_median=%f", translational_median);
5008 UINFO(
"translational_std=%f", translational_std);
5009 UINFO(
"translational_min=%f", translational_min);
5010 UINFO(
"translational_max=%f", translational_max);
5012 UINFO(
"rotational_rmse=%f", rotational_rmse);
5013 UINFO(
"rotational_mean=%f", rotational_mean);
5014 UINFO(
"rotational_median=%f", rotational_median);
5015 UINFO(
"rotational_std=%f", rotational_std);
5016 UINFO(
"rotational_min=%f", rotational_min);
5017 UINFO(
"rotational_max=%f", rotational_max);
5019 if(
ui_->checkBox_alignPosesWithGroundTruth->isChecked() && !gtToMap.
isIdentity())
5021 for(std::map<int, Transform>::iterator iter=graph.begin(); iter!=graph.end(); ++iter)
5023 iter->second = gtToMap * iter->second;
5028 std::map<int, rtabmap::Transform> graphFiltered;
5035 graphFiltered = graph;
5037 if(
ui_->groupBox_posefiltering->isChecked())
5040 ui_->doubleSpinBox_posefilteringRadius->value(),
5041 ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0);
5043 std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> > localMaps;
5044 std::map<int, std::pair<float, cv::Point3f> > localMapsInfo;
5045 #ifdef RTABMAP_OCTOMAP 5052 if(
ui_->dockWidget_graphView->isVisible() ||
ui_->dockWidget_occupancyGridView->isVisible())
5055 UINFO(
"Update local maps list...");
5056 std::vector<int> ids =
uKeys(graphFiltered);
5057 for(
unsigned int i=0; i<ids.size(); ++i)
5066 if(!
localMaps_.find(ids[i])->second.first.first.empty() || !
localMaps_.find(ids[i])->second.first.second.empty())
5068 localMaps.insert(*
localMaps_.find(ids.at(i)));
5076 cv::Mat ground, obstacles, empty;
5078 localMaps_.insert(std::make_pair(ids.at(i), std::make_pair(std::make_pair(ground, obstacles), empty)));
5080 if(!ground.empty() || !obstacles.empty())
5082 localMaps.insert(std::make_pair(ids.at(i), std::make_pair(std::make_pair(ground, obstacles), empty)));
5088 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=
localMaps_.begin(); iter!=
localMaps_.end();)
5090 if(graphFiltered.find(iter->first) == graphFiltered.end())
5100 UINFO(
"Update local maps list... done (%d local maps, graph size=%d)", (
int)localMaps.size(), (int)graph.size());
5104 float cellSize = Parameters::defaultGridCellSize();
5110 ui_->graphViewer->clearMap();
5112 if(graph.size() && localMaps.size() &&
5113 (
ui_->graphViewer->isGridMapVisible() ||
ui_->dockWidget_occupancyGridView->isVisible()))
5118 #ifdef RTABMAP_OCTOMAP 5119 if(
ui_->checkBox_octomap->isChecked())
5122 bool updateAborted =
false;
5123 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
5125 if(iter->second.first.first.channels() == 2 || iter->second.first.second.channels() == 2)
5127 QMessageBox::warning(
this, tr(
""),
5128 tr(
"Some local occupancy grids are 2D, but OctoMap requires 3D local " 5129 "occupancy grids. Uncheck OctoMap under GUI parameters or generate " 5130 "3D local occupancy grids (\"Grid/3D\" core parameter)."));
5131 updateAborted =
true;
5134 octomap_->
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second, localMapsInfo.at(iter->first).second);
5144 if((
ui_->dockWidget_graphView->isVisible() &&
ui_->graphViewer->isGridMapVisible()) ||
5145 (
ui_->dockWidget_occupancyGridView->isVisible() &&
ui_->checkBox_grid_2d->isChecked()))
5147 bool eroded = Parameters::defaultGridGlobalEroded();
5152 #ifdef RTABMAP_OCTOMAP 5153 if(
ui_->checkBox_octomap->isChecked())
5166 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
5168 grid.
addToCache(iter->first, iter->second.first.first, iter->second.first.second, iter->second.second);
5170 grid.
update(graphFiltered);
5171 map = grid.
getMap(xMin, yMin);
5174 ui_->label_timeGrid->setNum(
double(time.elapsed())/1000.0);
5179 if(
ui_->dockWidget_graphView->isVisible() &&
ui_->graphViewer->isGridMapVisible())
5181 ui_->graphViewer->updateMap(map8U, cellSize, xMin, yMin);
5183 if(
ui_->dockWidget_occupancyGridView->isVisible() &&
ui_->checkBox_grid_2d->isChecked())
5192 if(
ui_->dockWidget_occupancyGridView->isVisible())
5194 #ifdef RTABMAP_OCTOMAP 5195 if(
ui_->checkBox_octomap->isChecked())
5202 pcl::PointCloud<pcl::PointXYZ>::Ptr groundXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
5203 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
5204 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCellsXYZ(
new pcl::PointCloud<pcl::PointXYZ>);
5205 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
5206 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
5207 pcl::PointCloud<pcl::PointXYZRGB>::Ptr emptyCellsRGB(
new pcl::PointCloud<pcl::PointXYZRGB>);
5209 for(std::map<
int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=localMaps.begin(); iter!=localMaps.end(); ++iter)
5211 Transform pose = graphFiltered.at(iter->first);
5215 if(!iter->second.first.first.empty())
5217 if(iter->second.first.first.channels() == 4)
5226 if(!iter->second.first.second.empty())
5228 if(iter->second.first.second.channels() == 4)
5237 if(
ui_->checkBox_grid_empty->isChecked())
5239 if(!iter->second.second.empty())
5241 if(iter->second.second.channels() == 4)
5253 if(groundRGB->size())
5259 QColor(
ui_->lineEdit_groundColor->text()));
5262 if(groundXYZ->size())
5268 QColor(
ui_->lineEdit_groundColor->text()));
5271 if(obstaclesRGB->size())
5277 QColor(
ui_->lineEdit_obstacleColor->text()));
5280 if(obstaclesXYZ->size())
5286 QColor(
ui_->lineEdit_obstacleColor->text()));
5289 if(emptyCellsRGB->size())
5295 QColor(
ui_->lineEdit_emptyColor->text()));
5299 if(emptyCellsXYZ->size())
5305 QColor(
ui_->lineEdit_emptyColor->text()));
5313 ui_->graphViewer->fitInView(
ui_->graphViewer->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
5314 ui_->graphViewer->update();
5315 ui_->label_iterations->setNum(value);
5319 for(std::multimap<int, rtabmap::Link>::const_iterator iter=
graphLinks_.begin(); iter!=
graphLinks_.end(); ++iter)
5321 std::map<int, rtabmap::Transform>::const_iterator jterA = graph.find(iter->first);
5322 std::map<int, rtabmap::Transform>::const_iterator jterB = graph.find(iter->second.to());
5323 if(jterA != graph.end() && jterB != graph.end())
5330 Eigen::Vector3f vA, vB;
5333 vA[0] = x; vA[1] = y; vA[2] = z;
5335 vB[0] = x; vB[1] = y; vB[2] = z;
5336 length += (vB - vA).norm();
5340 ui_->label_pathLength->setNum(length);
5345 ui_->label_loopClosures->clear();
5346 ui_->label_poses->clear();
5347 ui_->label_rmse->clear();
5351 int fromId =
ui_->spinBox_optimizationsFrom->value();
5354 QMessageBox::warning(
this, tr(
""), tr(
"Graph optimization from id (%1) for which node is not linked to graph.\n Minimum=%2, Maximum=%3")
5361 std::map<int, Transform> optimizedGraphGuess;
5370 std::map<int, rtabmap::Transform> poses =
odomPoses_;
5373 std::map<int, rtabmap::Transform> wmPoses;
5374 std::vector<int> & wmState =
wmStates_.at(fromId);
5375 for(
unsigned int i=0; i<wmState.size(); ++i)
5377 std::map<int, rtabmap::Transform>::iterator iter = poses.find(wmState[i]);
5378 if(iter!=poses.end())
5380 wmPoses.insert(*iter);
5383 if(!wmPoses.empty())
5389 UWARN(
"Empty WM poses!? Ignoring WM state... (root id=%d, wmState=%d)", fromId, wmState.size());
5396 int currentMapId =
mapIds_.at(fromId);
5397 for(std::map<int, rtabmap::Transform>::iterator iter=poses.begin(); iter!=poses.end();)
5400 mapIds_.at(iter->first) != currentMapId)
5402 poses.erase(iter++);
5411 ui_->menuExport_poses->setEnabled(
true);
5412 std::multimap<int, rtabmap::Link> links =
links_;
5418 int currentMapId =
mapIds_.at(fromId);
5419 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end();)
5423 mapIds_.at(iter->second.from()) != currentMapId ||
5424 mapIds_.at(iter->second.to()) != currentMapId)
5426 links.erase(iter++);
5436 if(
ui_->checkBox_ignorePoseCorrection->isChecked())
5438 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
5445 if(!poseFrom.
isNull() && !poseTo.isNull())
5448 iter->second =
Link(
5449 iter->second.from(),
5451 iter->second.type(),
5459 int totalNeighbor = 0;
5460 int totalNeighborMerged = 0;
5461 int totalGlobal = 0;
5462 int totalLocalTime = 0;
5463 int totalLocalSpace = 0;
5465 int totalPriors = 0;
5466 for(std::multimap<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end();)
5474 ++totalNeighborMerged;
5478 if(
ui_->checkBox_ignoreGlobalLoop->isChecked())
5480 links.erase(iter++);
5488 if(
ui_->checkBox_ignoreLocalLoopSpace->isChecked())
5490 links.erase(iter++);
5498 if(
ui_->checkBox_ignoreLocalLoopTime->isChecked())
5500 links.erase(iter++);
5508 if(
ui_->checkBox_ignoreUserLoop->isChecked())
5510 links.erase(iter++);
5528 ui_->label_loopClosures->setText(tr(
"(%1, %2, %3, %4, %5, %6, %7)")
5530 .arg(totalNeighborMerged)
5532 .arg(totalLocalSpace)
5533 .arg(totalLocalTime)
5538 if(
ui_->checkBox_ignoreIntermediateNodes->isVisible() &&
5539 ui_->checkBox_ignoreIntermediateNodes->isChecked())
5541 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
5546 Link link = iter->second;
5549 std::multimap<int, Link>::iterator uter = links.find(link.
to());
5550 if(uter != links.end())
5553 poses.erase(link.
to());
5554 link = link.
merge(uter->second, uter->second.type());
5563 iter->second = link;
5572 std::map<int, rtabmap::Transform> posesOut;
5573 std::multimap<int, rtabmap::Link> linksOut;
5574 UINFO(
"Get connected graph from %d (%d poses, %d links)", fromId, (
int)poses.size(), (int)links.size());
5581 ui_->spinBox_optimizationDepth->value());
5582 if(optimizedGraphGuess.size() == posesOut.size())
5584 bool identical=
true;
5585 for(std::map<int, Transform>::iterator iter=posesOut.begin(); iter!=posesOut.end(); ++iter)
5587 if(!
uContains(optimizedGraphGuess, iter->first))
5595 posesOut = optimizedGraphGuess;
5598 UINFO(
"Connected graph of %d poses and %d links", (
int)posesOut.size(), (int)linksOut.size());
5601 std::map<int, rtabmap::Transform> finalPoses = optimizer->
optimize(fromId, posesOut, linksOut,
ui_->checkBox_iterativeOptimization->isChecked()?&
graphes_:0);
5602 ui_->label_timeOptimization->setNum(
double(time.elapsed())/1000.0);
5605 ui_->label_poses->setNum((
int)finalPoses.size());
5606 if(posesOut.size() && finalPoses.empty())
5608 UWARN(
"Optimization failed, trying incremental optimization instead... this may take a while (poses=%d, links=%d).", (
int)posesOut.size(), (int)linksOut.size());
5611 if(finalPoses.empty())
5613 UWARN(
"Incremental optimization also failed.");
5616 QMessageBox::warning(
this, tr(
"Graph optimization error!"), tr(
"Graph optimization has failed. See the terminal for potential errors. " 5617 "Give it a try with %1=0 and %2=true.").arg(Parameters::kOptimizerStrategy().c_str()).arg(Parameters::kOptimizerVarianceIgnored().c_str()));
5621 QMessageBox::warning(
this, tr(
"Graph optimization error!"), tr(
"Graph optimization has failed. See the terminal for potential errors."));
5626 UWARN(
"Incremental optimization succeeded!");
5627 QMessageBox::information(
this, tr(
"Incremental optimization succeeded!"), tr(
"Graph optimization has failed but " 5628 "incremental optimization succeeded. Next optimizations will use the current " 5629 "best optimized poses as first guess instead of odometry poses."));
5639 if(
ui_->doubleSpinBox_optimizationScale->value()!=-1.0)
5642 for(std::list<std::map<int, Transform> >::iterator iter=
graphes_.begin(); iter!=
graphes_.end(); ++iter)
5644 for(std::map<int, Transform>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
5646 jter->second = jter->second.clone();
5647 jter->second.x() *=
ui_->doubleSpinBox_optimizationScale->value();
5648 jter->second.y() *=
ui_->doubleSpinBox_optimizationScale->value();
5649 jter->second.z() *=
ui_->doubleSpinBox_optimizationScale->value();
5654 ui_->horizontalSlider_iterations->setMaximum((
int)
graphes_.size()-1);
5655 ui_->horizontalSlider_iterations->setValue((
int)
graphes_.size()-1);
5656 ui_->horizontalSlider_iterations->setEnabled(
true);
5657 ui_->spinBox_optimizationsFrom->setEnabled(
true);
5662 ui_->horizontalSlider_iterations->setEnabled(
false);
5663 ui_->spinBox_optimizationsFrom->setEnabled(
false);
5669 if(sender() ==
ui_->checkBox_grid_2d && !
ui_->checkBox_grid_2d->isChecked())
5677 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
5678 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
5679 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
5680 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
5681 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
5682 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
5691 #ifdef RTABMAP_OCTOMAP 5692 ui_->comboBox_octomap_rendering_type->setVisible(
ui_->checkBox_octomap->isChecked());
5693 ui_->spinBox_grid_depth->setVisible(
ui_->checkBox_octomap->isChecked());
5694 ui_->checkBox_grid_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
5695 ui_->label_octomap_cubes->setVisible(
ui_->checkBox_octomap->isChecked());
5696 ui_->label_octomap_depth->setVisible(
ui_->checkBox_octomap->isChecked());
5697 ui_->label_octomap_empty->setVisible(!
ui_->checkBox_octomap->isChecked() ||
ui_->comboBox_octomap_rendering_type->currentIndex()==0);
5699 if(
ui_->checkBox_octomap->isChecked())
5706 if(
ui_->comboBox_octomap_rendering_type->currentIndex()>0)
5712 pcl::IndicesPtr obstacles(
new std::vector<int>);
5713 pcl::IndicesPtr empty(
new std::vector<int>);
5714 pcl::IndicesPtr ground(
new std::vector<int>);
5715 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud =
octomap_->
createCloud(
ui_->spinBox_grid_depth->value(), obstacles.get(), empty.get(), ground.get());
5719 pcl::PointCloud<pcl::PointXYZRGB>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
5720 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
5724 pcl::PointCloud<pcl::PointXYZRGB>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
5725 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
5731 pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesCloud(
new pcl::PointCloud<pcl::PointXYZ>);
5732 pcl::copyPointCloud(*cloud, *obstacles, *obstaclesCloud);
5736 pcl::PointCloud<pcl::PointXYZ>::Ptr groundCloud(
new pcl::PointCloud<pcl::PointXYZ>);
5737 pcl::copyPointCloud(*cloud, *ground, *groundCloud);
5742 if(
ui_->checkBox_grid_empty->isChecked())
5744 pcl::PointCloud<pcl::PointXYZ>::Ptr emptyCloud(
new pcl::PointCloud<pcl::PointXYZ>);
5745 pcl::copyPointCloud(*cloud, *empty, *emptyCloud);
5753 if(
ui_->dockWidget_view3d->isVisible() &&
ui_->checkBox_showGrid->isChecked())
5767 link = findIter->second;
5774 link = findIter->second;
5779 if(findIter !=
links_.end())
5781 link = findIter->second;
5795 int from =
ids_.at(
ui_->horizontalSlider_A->value());
5796 int to =
ids_.at(
ui_->horizontalSlider_B->value());
5804 UWARN(
"Cannot refine link to same node");
5811 UERROR(
"Not found link! (%d->%d)", from, to);
5814 UDEBUG(
"%d -> %d (type=%d)", from ,to, currentLink.
type());
5816 if(
ui_->checkBox_showOptimized->isChecked() &&
5819 (int)
graphes_.size()-1 ==
ui_->horizontalSlider_iterations->maximum())
5821 std::map<int, rtabmap::Transform> & graph =
uValueAt(
graphes_,
ui_->horizontalSlider_iterations->value());
5824 std::map<int, rtabmap::Transform>::iterator iterFrom = graph.find(currentLink.
from());
5825 std::map<int, rtabmap::Transform>::iterator iterTo = graph.find(currentLink.
to());
5826 if(iterFrom != graph.end() && iterTo != graph.end())
5833 else if(
ui_->checkBox_ignorePoseCorrection->isChecked() &&
5841 if(!poseFrom.
isNull() && !poseTo.isNull())
5843 t = poseFrom.
inverse() * poseTo;
5862 std::map<int, rtabmap::Transform> scanPoses;
5866 userData.type() == CV_8SC1 &&
5867 userData.rows == 1 &&
5868 userData.cols >= 8 &&
5869 userData.at<
char>(userData.cols-1) == 0 &&
5870 memcmp(userData.data,
"SCANS:", 6) == 0 &&
5871 currentLink.
from() > currentLink.
to())
5873 std::string scansStr = (
const char *)userData.data;
5874 UINFO(
"Detected \"%s\" in links's user data", scansStr.c_str());
5875 if(!scansStr.empty())
5877 std::list<std::string> strs =
uSplit(scansStr,
':');
5878 if(strs.size() == 2)
5880 std::list<std::string> strIds =
uSplit(strs.rbegin()->c_str(),
';');
5881 for(std::list<std::string>::iterator iter=strIds.begin(); iter!=strIds.end(); ++iter)
5883 int id = atoi(iter->c_str());
5890 UERROR(
"Not found %d node!",
id);
5896 if(scanPoses.size())
5902 std::map<int, rtabmap::Transform> posesOut;
5903 std::multimap<int, rtabmap::Link> linksOut;
5911 if(scanPoses.size() != posesOut.size())
5913 UWARN(
"Scan poses input and output are different! %d vs %d", (
int)scanPoses.size(), (int)posesOut.size());
5914 UWARN(
"Input poses: ");
5915 for(std::map<int, Transform>::iterator iter=scanPoses.begin(); iter!=scanPoses.end(); ++iter)
5917 UWARN(
" %d", iter->first);
5919 UWARN(
"Input links: ");
5921 for(std::multimap<int, Link>::iterator iter=modifiedLinks.begin(); iter!=modifiedLinks.end(); ++iter)
5923 UWARN(
" %d->%d", iter->second.from(), iter->second.to());
5927 scanPoses = optimizer->
optimize(currentLink.
to(), posesOut, linksOut);
5930 std::map<int, Transform> filteredScanPoses = scanPoses;
5931 float proximityFilteringRadius = 0.0f;
5932 Parameters::parse(parameters, Parameters::kRGBDProximityPathFilteringRadius(), proximityFilteringRadius);
5933 if(scanPoses.size() > 2 && proximityFilteringRadius > 0.0f)
5938 filteredScanPoses.insert(*scanPoses.find(currentLink.
to()));
5944 int maxPoints = fromScan.
size();
5945 pcl::PointCloud<pcl::PointXYZ>::Ptr assembledToClouds(
new pcl::PointCloud<pcl::PointXYZ>);
5946 pcl::PointCloud<pcl::PointNormal>::Ptr assembledToNormalClouds(
new pcl::PointCloud<pcl::PointNormal>);
5947 for(std::map<int, Transform>::const_iterator iter = filteredScanPoses.begin(); iter!=filteredScanPoses.end(); ++iter)
5949 if(iter->first != currentLink.
from())
5968 if(scan.
size() > maxPoints)
5970 maxPoints = scan.
size();
5976 UWARN(
"Laser scan not found for signature %d", iter->first);
5981 cv::Mat assembledScan;
5982 if(assembledToNormalClouds->size())
5986 else if(assembledToClouds->size())
6014 if(
ui_->checkBox_icp_from_depth->isChecked())
6017 cv::Mat tmpA, tmpB, tmpC, tmpD;
6022 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
6023 ui_->doubleSpinBox_icp_maxDepth->value(),
6024 ui_->doubleSpinBox_icp_minDepth->value(),
6026 ui_->parameters_toolbox->getParameters());
6029 ui_->spinBox_icp_decimation->value()==0?1:
ui_->spinBox_icp_decimation->value(),
6030 ui_->doubleSpinBox_icp_maxDepth->value(),
6031 ui_->doubleSpinBox_icp_minDepth->value(),
6033 ui_->parameters_toolbox->getParameters());
6034 int maxLaserScans = cloudFrom->size();
6040 UWARN(
"There are laser scans in data, but generate laser scan from " 6041 "depth image option is activated. Ignoring saved laser scans...");
6054 cv::Mat tmpA, tmpB, tmpC, tmpD;
6059 UINFO(
"Uncompress time: %f s", timer.
ticks());
6064 delete registration;
6066 UINFO(
"(%d ->%d) Registration time: %f s", from, to, timer.
ticks());
6074 info.
covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001;
6079 bool updated =
false;
6080 std::multimap<int, Link>::iterator iter =
linksRefined_.find(currentLink.
from());
6083 if(iter->second.to() == currentLink.
to() &&
6084 iter->second.type() == currentLink.
type())
6086 iter->second = newLink;
6094 linksRefined_.insert(std::make_pair(newLink.from(), newLink));
6102 if(!silent &&
ui_->dockWidget_constraints->isVisible())
6104 if(fromS.
id() > 0 && toS.
id() > 0)
6121 QMessageBox::warning(
this,
6123 tr(
"Cannot find a transformation between nodes %1 and %2: %3").arg(from).arg(to).arg(info.
rejectedMsg.c_str()));
6129 int from =
ids_.at(
ui_->horizontalSlider_A->value());
6130 int to =
ids_.at(
ui_->horizontalSlider_B->value());
6136 bool switchedIds =
false;
6139 UWARN(
"Cannot add link to same node");
6164 ids.push_back(from);
6166 std::list<Signature*> signatures;
6168 if(signatures.size() != 2)
6170 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
6176 Signature * fromS = *signatures.begin();
6179 bool reextractVisualFeatures =
uStr2Bool(parameters.at(Parameters::kRGBDLoopClosureReextractFeatures()));
6182 reextractVisualFeatures)
6189 if(reextractVisualFeatures)
6191 fromS->
setWords(std::multimap<int, cv::KeyPoint>());
6192 fromS->
setWords3(std::multimap<int, cv::Point3f>());
6194 fromS->
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
6195 toS->
setWords(std::multimap<int, cv::KeyPoint>());
6196 toS->
setWords3(std::multimap<int, cv::Point3f>());
6201 else if(!reextractVisualFeatures && fromS->
getWords().empty() && toS->
getWords().empty())
6203 UWARN(
"\"%s\" is false and signatures (%d and %d) don't have words, " 6204 "registration will not be possible. Set \"%s\" to true.",
6205 Parameters::kRGBDLoopClosureReextractFeatures().c_str(),
6208 Parameters::kRGBDLoopClosureReextractFeatures().c_str());
6238 info.
covariance = cv::Mat::eye(6,6,CV_64FC1)*0.0001;
6245 QMessageBox::warning(
this,
6247 tr(
"Cannot find a transformation between nodes %1 and %2: %3").arg(from).arg(to).arg(info.
rejectedMsg.c_str()));
6250 for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
6260 bool updateConstraints = newLink.
isValid();
6261 float maxOptimizationError =
uStr2Float(
ui_->parameters_toolbox->getParameters().at(Parameters::kRGBDOptimizeMaxError()));
6263 maxOptimizationError > 0.0f &&
6264 uStr2Int(
ui_->parameters_toolbox->getParameters().at(Parameters::kOptimizerIterations())) > 0.0
f)
6266 int fromId = newLink.
from();
6269 for(std::map<int, int>::iterator iter=
mapIds_.begin(); iter!=
mapIds_.end(); ++iter)
6271 if(iter->second == mapId)
6273 fromId = iter->first;
6278 linksIn.insert(std::make_pair(newLink.
from(), newLink));
6279 const Link * maxLinearLink = 0;
6280 const Link * maxAngularLink = 0;
6281 float maxLinearErrorRatio = 0.0f;
6282 float maxAngularErrorRatio = 0.0f;
6284 std::map<int, Transform> poses;
6285 std::multimap<int, Link> links;
6290 UASSERT(poses.find(fromId) != poses.end());
6291 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());
6292 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());
6294 poses = optimizer->
optimize(fromId, poses, links);
6298 float maxLinearError = 0.0f;
6299 float maxAngularError = 0.0f;
6300 for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
6303 if(iter->second.transVariance() <= 1.0 && iter->second.from() != iter->second.to())
6308 float linearError =
uMax3(
6309 fabs(iter->second.transform().x() - t.x()),
6310 fabs(iter->second.transform().y() - t.y()),
6311 fabs(iter->second.transform().z() - t.z()));
6312 float opt_roll,opt__pitch,opt__yaw;
6313 float link_roll,link_pitch,link_yaw;
6314 t.getEulerAngles(opt_roll, opt__pitch, opt__yaw);
6315 iter->second.transform().getEulerAngles(link_roll, link_pitch, link_yaw);
6316 float angularError =
uMax3(
6317 fabs(opt_roll - link_roll),
6318 fabs(opt__pitch - link_pitch),
6319 fabs(opt__yaw - link_yaw));
6320 float stddevLinear =
sqrt(iter->second.transVariance());
6321 float linearErrorRatio = linearError/stddevLinear;
6322 if(linearErrorRatio > maxLinearErrorRatio)
6324 maxLinearError = linearError;
6325 maxLinearErrorRatio = linearErrorRatio;
6326 maxLinearLink = &iter->second;
6328 float stddevAngular =
sqrt(iter->second.rotVariance());
6329 float angularErrorRatio = angularError/stddevAngular;
6330 if(angularErrorRatio > maxAngularErrorRatio)
6332 maxAngularError = angularError;
6333 maxAngularErrorRatio = angularErrorRatio;
6334 maxAngularLink = &iter->second;
6340 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()));
6341 if(maxLinearErrorRatio > maxOptimizationError)
6343 msg =
uFormat(
"Rejecting edge %d->%d because " 6344 "graph error is too large after optimization (ratio %f for edge %d->%d, stddev=%f). " 6348 maxLinearErrorRatio,
6349 maxLinearLink->
from(),
6350 maxLinearLink->
to(),
6352 Parameters::kRGBDOptimizeMaxError().c_str(),
6353 maxOptimizationError);
6358 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()));
6359 if(maxAngularErrorRatio > maxOptimizationError)
6361 msg =
uFormat(
"Rejecting edge %d->%d because " 6362 "graph error is too large after optimization (ratio %f for edge %d->%d, stddev=%f). " 6366 maxAngularErrorRatio,
6367 maxAngularLink->
from(),
6368 maxAngularLink->
to(),
6370 Parameters::kRGBDOptimizeMaxError().c_str(),
6371 maxOptimizationError);
6377 msg =
uFormat(
"Rejecting edge %d->%d because graph optimization has failed!",
6383 UWARN(
"%s", msg.c_str());
6386 QMessageBox::warning(
this,
6388 tr(
"%1").arg(msg.c_str()));
6391 updateConstraints =
false;
6395 if(updateConstraints)
6413 return updateConstraints;
6418 int from =
ids_.at(
ui_->horizontalSlider_A->value());
6419 int to =
ids_.at(
ui_->horizontalSlider_B->value());
6429 UWARN(
"Cannot reset link to same node");
6455 int from =
ids_.at(
ui_->horizontalSlider_A->value());
6456 int to =
ids_.at(
ui_->horizontalSlider_B->value());
6466 UWARN(
"Cannot reject link to same node");
6470 bool removed =
false;
6473 std::multimap<int, Link>::iterator iter;
6479 UWARN(
"Cannot reject neighbor links (%d->%d)", from, to);
6507 const std::multimap<int, rtabmap::Link> & edgeConstraints)
6509 std::multimap<int, rtabmap::Link> links;
6510 for(std::multimap<int, rtabmap::Link>::const_iterator iter=edgeConstraints.begin();
6511 iter!=edgeConstraints.end();
6514 std::multimap<int, rtabmap::Link>::iterator findIter;
6519 if(!(iter->second.from() == findIter->second.from() &&
6520 iter->second.to() == findIter->second.to() &&
6521 iter->second.type() == findIter->second.type()))
6523 UWARN(
"Links (%d->%d,%d) and (%d->%d,%d) are not equal!?",
6524 iter->second.from(), iter->second.to(), iter->second.type(),
6525 findIter->second.from(), findIter->second.to(), findIter->second.type());
6537 if(iter->second.from() == findIter->second.from() &&
6538 iter->second.to() == findIter->second.to() &&
6539 iter->second.type() == findIter->second.type())
6541 links.insert(*findIter);
6547 UWARN(
"Links (%d->%d,%d) and (%d->%d,%d) are not equal!?",
6548 iter->second.from(), iter->second.to(), iter->second.type(),
6549 findIter->second.from(), findIter->second.to(), findIter->second.type());
6553 links.insert(*iter);
6557 for(std::multimap<int, rtabmap::Link>::const_iterator iter=
linksAdded_.begin();
6562 links.insert(*iter);
6573 int position =
ui_->horizontalSlider_loops->value();
6574 std::multimap<int, Link> linksSortedByParents;
6575 for(std::multimap<int, rtabmap::Link>::iterator iter = links.begin(); iter!=links.end(); ++iter)
6577 if(iter->second.to() > iter->second.from())
6579 linksSortedByParents.insert(std::make_pair(iter->second.to(), iter->second.inverse()));
6583 linksSortedByParents.insert(*iter);
6586 for(std::multimap<int, rtabmap::Link>::iterator iter = linksSortedByParents.begin(); iter!=linksSortedByParents.end(); ++iter)
6588 if(!iter->second.transform().isNull())
6593 if((iter->second.from() == from && iter->second.to() == to) ||
6594 (iter->second.to() == from && iter->second.from() == to))
6603 UERROR(
"Transform null for link from %d to %d", iter->first, iter->second.to());
6614 ui_->horizontalSlider_loops->setMinimum(0);
6615 ui_->horizontalSlider_loops->setMaximum(
loopLinks_.size()-1);
6616 ui_->horizontalSlider_loops->setEnabled(
true);
6617 if(position !=
ui_->horizontalSlider_loops->value())
6619 ui_->horizontalSlider_loops->setValue(position);
6628 ui_->horizontalSlider_loops->setEnabled(
false);
6639 for(QStringList::const_iterator iter=parametersChanged.constBegin();
6640 iter!=parametersChanged.constEnd() && (!updateStereo || !
updateGraphView);
6643 QString group = iter->split(
'/').first();
6644 if(!updateStereo && group ==
"Stereo")
6646 updateStereo =
true;
6649 if(!updateGraphView && group ==
"Optimize")
6651 updateGraphView =
true;
const std::multimap< int, cv::Point3f > & getWords3() const
int UTILITE_EXP uStr2Int(const std::string &str)
void removeGraph(const std::string &id)
LaserScan RTABMAP_EXP laserScanFromPointCloud(const pcl::PCLPointCloud2 &cloud, bool filterNaNs=true)
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)
int sessionExported() const
std::map< int, std::pair< float, cv::Point3f > > generatedLocalMapsInfo_
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)
void incrementStep(int steps=1)
cv::Mat loadOptimizedMesh(std::vector< std::vector< std::vector< unsigned int > > > *polygons=0, std::vector< std::vector< Eigen::Vector2f > > *texCoords=0, cv::Mat *textures=0) const
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)
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 >(), bool g2oRobust=false)
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)
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
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)
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP transformPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const Transform &transform)
V & uValueAt(std::list< V > &list, const unsigned int &pos)
const std::multimap< int, cv::KeyPoint > & getWords() const
bool isGainCompensation() const
void setWords3(const std::multimap< int, cv::Point3f > &words3)
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 loadLinks(int signatureId, std::map< int, Link > &links, Link::Type type=Link::kUndef) const
void update(const std::map< int, Transform > &poses)
static int channels(Format format)
void setWords(const std::multimap< int, cv::KeyPoint > &words)
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)
Transform computeTransformation(const Signature &from, const Signature &to, Transform guess=Transform::getIdentity(), RegistrationInfo *info=0) const
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)
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)
std::pair< std::string, std::string > ParametersPair
std::list< std::map< int, rtabmap::Transform > > graphes_
pcl::PointCloud< pcl::PointXYZRGBNormal >::Ptr RTABMAP_EXP laserScanToPointCloudRGBNormal(const LaserScan &laserScan, const Transform &transform=Transform(), unsigned char r=255, unsigned char g=255, unsigned char b=255)
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)
std::vector< cv::KeyPoint > generateKeypoints(const cv::Mat &image, const cv::Mat &mask=cv::Mat()) const
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP removeNaNFromPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud)
void getAllLinks(std::multimap< int, Link > &links, bool ignoreNullLinks=true) const
pcl::PCLPointCloud2::Ptr RTABMAP_EXP laserScanToPointCloud2(const LaserScan &laserScan, const Transform &transform=Transform())
long getWordsMemoryUsed() const
void updateConstraintView()
float UTILITE_EXP uStr2Float(const std::string &str)
double transVariance() const
void exportGPS(int format)
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
bool addOccupancyGridMap(const cv::Mat &map8U, float resolution, float xMin, float yMin, float opacity)
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 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
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)
double rotVariance() const
void update(const std::map< int, Transform > &poses)
Some conversion functions.
const cv::Mat & gridGroundCellsRaw() const
void addValue(UPlotItem *data)
const std::string & getUrl() const
void setImage(const QImage &image)
void setPolygonPicking(bool enabled)
bool getNodeInfo(int signatureId, Transform &pose, int &mapId, int &weight, std::string &label, double &stamp, Transform &groundTruthPose, std::vector< float > &velocity, GPS &gps) const
std::multimap< int, rtabmap::Link > linksAdded_
const LaserScan & laserScanRaw() 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 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 *labeCalib, QLabel *labelGps, bool updateConstraintView)
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 refineAllLoopClosureLinks()
const Transform & transform() const
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP laserScanToPointCloud(const LaserScan &laserScan, const Transform &transform=Transform())
const double & altitude() const
const double & longitude() const
QMap< int, int > idToIndex_
T uMin(const T *v, unsigned int size, unsigned int &index)
std::vector< std::vector< unsigned int > > RTABMAP_EXP convertPolygonsFromPCL(const std::vector< pcl::Vertices > &polygons)
void setDBDriver(const DBDriver *dbDriver)
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= ' ')
bool addCloud(const std::string &id, const pcl::PCLPointCloud2Ptr &binaryCloud, const Transform &pose, bool rgb, bool hasNormals, bool hasIntensity, const QColor &color=QColor())
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::map< int, Transform > lastOptimizedGraph_
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
cv::Mat getModifiedImage() const
void setupMainLayout(bool vertical)
std::map< int, Transform > optimizeIncremental(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)
void selectObstacleColor()
void addToCache(int nodeId, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &ground, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &obstacles, const pcl::PointXYZ &viewPoint)
bool 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)
T uMax3(const T &a, const T &b, const T &c)
virtual ~DatabaseViewer()
static Feature2D * create(const ParametersMap ¶meters=ParametersMap())
std::map< int, int > mapIds_
#define ULOGGER_DEBUG(...)
std::map< int, GPS > gpsValues_
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 loadSignatures(const std::list< int > &ids, std::list< Signature * > &signatures, std::set< int > *loadedFromTrash=0)
void setImageDepth(const cv::Mat &imageDepth)
bool useLastOptimizedGraphAsGuess_
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)
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 >())
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
void setWordsDescriptors(const std::multimap< int, cv::Mat > &descriptors)
int getLastDictionarySize() 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) const
bool isExposeFusion() const
void sliderIterationsValueChanged(int)
void setMaximumSteps(int steps)
pcl::TextureMesh::Ptr RTABMAP_EXP assembleTextureMesh(const cv::Mat &cloudMat, const std::vector< std::vector< std::vector< unsigned int > > > &polygons, const std::vector< std::vector< Eigen::Vector2f > > &texCoords, cv::Mat &textures, bool mergeTextures=false)
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
std::map< int, int > weights_
std::multimap< int, rtabmap::Link > linksRemoved_
void saveOptimizedMesh(const cv::Mat &cloud, const std::vector< std::vector< std::vector< unsigned int > > > &polygons=std::vector< std::vector< std::vector< unsigned int > > >(), const std::vector< std::vector< Eigen::Vector2f > > &texCoords=std::vector< std::vector< Eigen::Vector2f > >(), const cv::Mat &textures=cv::Mat()) 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
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)
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())
CloudViewer * stereoViewer_
bool isFrustumShown() const
bool isRgbExported() 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)
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
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
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
ULogger class and convenient macros.
const StereoCameraModel & stereoCameraModel() const
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 forceAssembling(bool enabled)
int getTextureSize() const
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
void generateLocalGraph()
static 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, int depth=0)
bool addOctomap(const OctoMap *octomap, unsigned int treeDepth=0, bool volumeRepresentation=true)
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())
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,...)
void updateWordsMatching()
cv::Mat getMap(float &xMin, float &yMin) const
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 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
pcl::PointCloud< pcl::PointXYZRGB >::Ptr RTABMAP_EXP laserScanToPointCloudRGB(const LaserScan &laserScan, const Transform &transform=Transform(), unsigned char r=255, unsigned char g=255, unsigned char b=255)
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
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)
void setLaserScanRaw(const LaserScan &laserScanRaw)
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)
pcl::PolygonMesh::Ptr RTABMAP_EXP assemblePolygonMesh(const cv::Mat &cloudMat, const std::vector< std::vector< unsigned int > > &polygons)
const double & stamp() const