diff --git a/guilib/include/rtabmap/gui/MainWindow.h b/guilib/include/rtabmap/gui/MainWindow.h index 7a42cbe9..20c5f314 100644 --- a/guilib/include/rtabmap/gui/MainWindow.h +++ b/guilib/include/rtabmap/gui/MainWindow.h @@ -149,10 +149,9 @@ private slots: void setAspectRatio480p(); void setAspectRatio720p(); void setAspectRatio1080p(); - void savePointClouds(); - void saveMeshes(); - void viewPointClouds(); - void viewMeshes(); + void exportGridMap(); + void exportPointClouds(); + void viewClouds(); void resetOdometry(); void triggerNewMap(); void dataRecorder(); @@ -184,7 +183,13 @@ private: void updateSelectSourceDatabase(bool used); void updateSelectSourceRGBDMenu(bool used, PreferencesDialog::Src src); - pcl::PointCloud::Ptr createAssembledCloud(const std::map & poses) const; + pcl::PointCloud::Ptr getAssembledCloud( + const std::map & poses, + float assembledVoxelSize, + bool regenerateClouds, + int regenerateDecimation, + float regenerateVoxelSize, + float regenerateMaxDepth) const; pcl::PointCloud::Ptr createCloud( int id, const cv::Mat & rgb, @@ -198,10 +203,15 @@ private: float voxelSize, int decimation, float maxDepth) const; - std::map::Ptr > createPointClouds(const std::map & poses, bool applyMLS) const; - std::map createMeshes(const std::map & poses, bool applyMLS) const; + std::map::Ptr > getClouds( + const std::map & poses, + bool regenerateClouds, + int regenerateDecimation, + float regenerateVoxelSize, + float regenerateMaxDepth) const; - void savePointClouds(const std::map::Ptr> & clouds); + bool getExportedClouds(std::map::Ptr> & clouds, std::map & meshes, bool toSave); + void saveClouds(const std::map::Ptr> & clouds); void saveMeshes(const std::map & meshes); private: @@ -233,6 +243,7 @@ private: QMap _depthCysMap; QMap _localTransformsMap; std::map _currentPosesMap; + QMap::Ptr > _createdClouds; Transform _odometryCorrection; Transform _lastOdomPose; bool _lastOdometryProcessed; diff --git a/guilib/include/rtabmap/gui/PreferencesDialog.h b/guilib/include/rtabmap/gui/PreferencesDialog.h index 420e4455..f79b1ebc 100644 --- a/guilib/include/rtabmap/gui/PreferencesDialog.h +++ b/guilib/include/rtabmap/gui/PreferencesDialog.h @@ -113,22 +113,22 @@ public: int getKeypointsOpacity() const; int getOdomQualityWarnThr() const; - bool isCloudMeshing(int index) const; // 0=map - bool isCloudsShown(int index) const; // 0=map, 1=odom, 2=save - double getCloudVoxelSize(int index) const; // 0=map, 1=odom, 2=save - int getCloudDecimation(int index) const; // 0=map, 1=odom, 2=save - double getCloudMaxDepth(int index) const; // 0=map, 1=odom, 2=save + bool isCloudMeshing() const; + bool isCloudsShown(int index) const; // 0=map, 1=odom + double getCloudVoxelSize(int index) const; // 0=map, 1=odom + int getCloudDecimation(int index) const; // 0=map, 1=odom + double getCloudMaxDepth(int index) const; // 0=map, 1=odom double getCloudOpacity(int index) const; // 0=map, 1=odom int getCloudPointSize(int index) const; // 0=map, 1=odom - bool isScansShown(int index) const; // 0=map, 1=odom, 2=save + bool isScansShown(int index) const; // 0=map, 1=odom double getScanOpacity(int index) const; // 0=map, 1=odom int getScanPointSize(int index) const; // 0=map, 1=odom - int getMeshNormalKSearch(int index) const; // 0=map, 1=save - double getMeshGP3Radius(int index) const; // 0=map, 1=save - bool getMeshSmoothing(int index) const; // 0=map, 1=save - double getMeshSmoothingRadius(int index) const; // 0=map, 1=save + int getMeshNormalKSearch() const; + double getMeshGP3Radius() const; + bool getMeshSmoothing() const; + double getMeshSmoothingRadius() const; bool isCloudFiltering() const; double getCloudFilteringRadius() const; @@ -284,11 +284,6 @@ private: QVector _3dRenderingShowScans; QVector _3dRenderingOpacityScan; QVector _3dRenderingPtSizeScan; - QVector _3dRenderingMeshing; - QVector _3dRenderingNormalKSearch; - QVector _3dRenderingGP3Radius; - QVector _3dRenderingSmoothing; - QVector _3dRenderingSmoothingRadius; }; Q_DECLARE_OPERATORS_FOR_FLAGS(PreferencesDialog::PANEL_FLAGS) diff --git a/guilib/src/CMakeLists.txt b/guilib/src/CMakeLists.txt index 6a275531..a81ebd84 100644 --- a/guilib/src/CMakeLists.txt +++ b/guilib/src/CMakeLists.txt @@ -19,6 +19,7 @@ SET(headers_ui ../include/${PROJECT_PREFIX}/gui/DataRecorder.h ../include/${PROJECT_PREFIX}/gui/CalibrationDialog.h ./ExportDialog.h + ./ExportCloudsDialog.h ./MapVisibilityWidget.h ) @@ -30,6 +31,7 @@ SET(uis ./ui/DatabaseViewer.ui ./ui/loopClosureViewer.ui ./ui/exportDialog.ui + ./ui/exportCloudsDialog.ui ./ui/calibrationDialog.ui ) @@ -68,6 +70,7 @@ SET(SRC_FILES ./DataRecorder.cpp ./CalibrationDialog.cpp ./ExportDialog.cpp + ./ExportCloudsDialog.cpp ./MapVisibilityWidget.cpp ./GraphViewer.cpp ${moc_srcs} diff --git a/guilib/src/ExportCloudsDialog.cpp b/guilib/src/ExportCloudsDialog.cpp new file mode 100644 index 00000000..76f5c3f0 --- /dev/null +++ b/guilib/src/ExportCloudsDialog.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke + * + * This file is part of RTAB-Map. + * + * RTAB-Map is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RTAB-Map is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RTAB-Map. If not, see . + */ + +#include "ExportCloudsDialog.h" +#include "ui_exportCloudsDialog.h" + +#include + +namespace rtabmap { + +ExportCloudsDialog::ExportCloudsDialog(QWidget *parent, bool toSave) : + QDialog(parent) +{ + _ui = new Ui_ExportCloudsDialog(); + _ui->setupUi(this); + if(toSave) + { + _ui->buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Save); + } +} + +ExportCloudsDialog::~ExportCloudsDialog() +{ + delete _ui; +} + +bool ExportCloudsDialog::getAssemble() const +{ + return _ui->groupBox_assemble->isChecked(); +} + +double ExportCloudsDialog::getAssembleVoxel() const +{ + return _ui->doubleSpinBox_voxelSize_assembled->value(); +} + +bool ExportCloudsDialog::getGenerate() const +{ + return _ui->groupBox_regenerate->isChecked(); +} + +int ExportCloudsDialog::getGenerateDecimation() const +{ + return _ui->spinBox_decimation->value(); +} + +double ExportCloudsDialog::getGenerateVoxel() const +{ + return _ui->doubleSpinBox_voxelSize->value(); +} + +double ExportCloudsDialog::getGenerateMaxDepth() const +{ + return _ui->doubleSpinBox_maxDepth->value(); +} + +bool ExportCloudsDialog::getMLS() const +{ + return _ui->groupBox_mls->isChecked(); +} + +double ExportCloudsDialog::getMLSRadius() const +{ + return _ui->doubleSpinBox_mlsRadius->value(); +} + +bool ExportCloudsDialog::getMesh() const +{ + return _ui->groupBox_gp3->isChecked(); +} + +int ExportCloudsDialog::getMeshNormalKSearch() const +{ + return _ui->spinBox_normalKSearch->value(); +} + +double ExportCloudsDialog::getMeshGp3Radius() const +{ + return _ui->doubleSpinBox_gp3Radius->value(); +} + + +} diff --git a/guilib/src/ExportCloudsDialog.h b/guilib/src/ExportCloudsDialog.h new file mode 100644 index 00000000..3facf327 --- /dev/null +++ b/guilib/src/ExportCloudsDialog.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke + * + * This file is part of RTAB-Map. + * + * RTAB-Map is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RTAB-Map is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RTAB-Map. If not, see . + */ + +#ifndef EXPORTCLOUDSDIALOG_H_ +#define EXPORTCLOUDSDIALOG_H_ + +#include + +class Ui_ExportCloudsDialog; + +namespace rtabmap { + +class ExportCloudsDialog : public QDialog +{ + Q_OBJECT + +public: + ExportCloudsDialog(QWidget *parent = 0, bool toSave = false); + + virtual ~ExportCloudsDialog(); + + bool getAssemble() const; + double getAssembleVoxel() const; + bool getGenerate() const; + int getGenerateDecimation() const; + double getGenerateVoxel() const; + double getGenerateMaxDepth() const; + bool getMLS() const; + double getMLSRadius() const; + bool getMesh() const; + int getMeshNormalKSearch() const; + double getMeshGp3Radius() const; + +private: + Ui_ExportCloudsDialog * _ui; +}; + +} + +#endif /* EXPORTCLOUDSDIALOG_H_ */ diff --git a/guilib/src/ExportDialog.h b/guilib/src/ExportDialog.h index 4de30adf..b521c275 100644 --- a/guilib/src/ExportDialog.h +++ b/guilib/src/ExportDialog.h @@ -51,4 +51,4 @@ private: } -#endif /* ABOUTDIALOG_H_ */ +#endif /* EXPORTDIALOG_H_ */ diff --git a/guilib/src/MainWindow.cpp b/guilib/src/MainWindow.cpp index da4008a0..24b9d915 100644 --- a/guilib/src/MainWindow.cpp +++ b/guilib/src/MainWindow.cpp @@ -41,6 +41,7 @@ #include "utilite/UPlot.h" #include "rtabmap/gui/UCv2Qt.h" +#include "ExportCloudsDialog.h" #include "AboutDialog.h" #include "PdfPlot.h" #include "StatsToolBox.h" @@ -255,19 +256,17 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : connect(_ui->action480p, SIGNAL(triggered()), this, SLOT(setAspectRatio480p())); connect(_ui->action720p, SIGNAL(triggered()), this, SLOT(setAspectRatio720p())); connect(_ui->action1080p, SIGNAL(triggered()), this, SLOT(setAspectRatio1080p())); - connect(_ui->actionSave_point_cloud, SIGNAL(triggered()), this, SLOT(savePointClouds())); - connect(_ui->actionSave_mesh_ply_vtk_stl, SIGNAL(triggered()), this, SLOT(saveMeshes())); - connect(_ui->actionView_high_res_point_cloud, SIGNAL(triggered()), this, SLOT(viewPointClouds())); - connect(_ui->actionView_point_cloud_as_mesh, SIGNAL(triggered()), this, SLOT(viewMeshes())); + connect(_ui->actionSave_point_cloud, SIGNAL(triggered()), this, SLOT(exportPointClouds())); + connect(_ui->actionExport_2D_Grid_map_bmp_png, SIGNAL(triggered()), this, SLOT(exportGridMap())); + connect(_ui->actionView_high_res_point_cloud, SIGNAL(triggered()), this, SLOT(viewClouds())); connect(_ui->actionReset_Odometry, SIGNAL(triggered()), this, SLOT(resetOdometry())); connect(_ui->actionTrigger_a_new_map, SIGNAL(triggered()), this, SLOT(triggerNewMap())); connect(_ui->actionData_recorder, SIGNAL(triggered()), this, SLOT(dataRecorder())); _ui->actionPause->setShortcut(Qt::Key_Space); _ui->actionSave_point_cloud->setEnabled(false); + _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false); _ui->actionView_high_res_point_cloud->setEnabled(false); - _ui->actionSave_mesh_ply_vtk_stl->setEnabled(false); - _ui->actionView_point_cloud_as_mesh->setEnabled(false); _ui->actionReset_Odometry->setEnabled(false); #if defined(Q_WS_MAC) || defined(Q_WS_WIN) @@ -1057,13 +1056,19 @@ void MainWindow::updateMapCloud(const std::map & posesIn, const if(posesIn.size()) { _currentPosesMap = posesIn; - if(_currentPosesMap.size() && !_ui->actionSave_point_cloud->isEnabled()) + if(_currentPosesMap.size()) { - //enable save cloud action - _ui->actionSave_point_cloud->setEnabled(true); - _ui->actionView_high_res_point_cloud->setEnabled(true); - _ui->actionSave_mesh_ply_vtk_stl->setEnabled(true); - _ui->actionView_point_cloud_as_mesh->setEnabled(true); + if(_depthsMap.size() && !_ui->actionSave_point_cloud->isEnabled()) + { + //enable save cloud action + _ui->actionSave_point_cloud->setEnabled(true); + _ui->actionView_high_res_point_cloud->setEnabled(true); + } + + if(_depths2DMap.size() && !_ui->actionExport_2D_Grid_map_bmp_png->isEnabled()) + { + _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(true); + } } } @@ -1238,21 +1243,21 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose) _preferencesDialog->getCloudDecimation(0), _preferencesDialog->getCloudMaxDepth(0)); - if(_preferencesDialog->isCloudMeshing(0)) + if(_preferencesDialog->isCloudMeshing()) { pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh); if(cloud->size()) { pcl::PointCloud::Ptr cloudWithNormals; - if(_preferencesDialog->getMeshSmoothing(0)) + if(_preferencesDialog->getMeshSmoothing()) { - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(0)); + cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius()); } else { - cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch(0)); + cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch()); } - mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius(0)); + mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius()); } if(mesh->polygons.size()) @@ -1263,15 +1268,18 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose) { UERROR("Adding mesh cloud %d to viewer failed!", nodeId); } - + else + { + _createdClouds.insert(nodeId, tmp); + } } } else { - if(_preferencesDialog->getMeshSmoothing(0)) + if(_preferencesDialog->getMeshSmoothing()) { pcl::PointCloud::Ptr cloudWithNormals; - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(0)); + cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius()); cloud->clear(); pcl::copyPointCloud(*cloudWithNormals, *cloud); } @@ -1279,6 +1287,10 @@ void MainWindow::createAndAddCloudToMap(int nodeId, const Transform & pose) { UERROR("Adding cloud %d to viewer failed!", nodeId); } + else + { + _createdClouds.insert(nodeId, cloud); + } } _ui->widget_cloudViewer->setCloudOpacity(cloudName, _preferencesDialog->getCloudOpacity(0)); @@ -2663,6 +2675,7 @@ void MainWindow::clearTheCache() _depthCxsMap.clear(); _depthCysMap.clear(); _localTransformsMap.clear(); + _createdClouds.clear(); _ui->widget_cloudViewer->removeAllClouds(); _ui->widget_cloudViewer->render(); _currentPosesMap.clear(); @@ -2671,8 +2684,6 @@ void MainWindow::clearTheCache() //disable save cloud action _ui->actionSave_point_cloud->setEnabled(false); _ui->actionView_high_res_point_cloud->setEnabled(false); - _ui->actionSave_mesh_ply_vtk_stl->setEnabled(false); - _ui->actionView_point_cloud_as_mesh->setEnabled(false); _likelihoodCurve->clear(); _rawLikelihoodCurve->clear(); _posteriorCurve->clear(); @@ -2857,258 +2868,147 @@ void MainWindow::setAspectRatio1080p() this->setAspectRatio((1080*16)/9, 1080); } -void MainWindow::savePointClouds() +void MainWindow::exportGridMap() { - int button = QMessageBox::question(this, - tr("One or multiple files?"), - tr("Merge all clouds together?" - "\n\nNote that all cloud generation parameters [decimation=%1, voxel=%2m, max depth=%3m] can be found in " - "Preferences -> GUI -> 3D Rendering under Exporting column.") - .arg(_preferencesDialog->getCloudDecimation(2)) - .arg(_preferencesDialog->getCloudVoxelSize(2)) - .arg(_preferencesDialog->getCloudMaxDepth(2)), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + double gridCellSize = 0.05; + bool gridUnknownSpaceFilled = true; + bool ok; + QInputDialog::getDouble(this, tr("Grid cell size"), tr("Size (m):"), gridCellSize, 0.01, 1, 2, &ok); + if(!ok) + { + return; + } + + QMessageBox::StandardButton b = QMessageBox::question(this, + tr("Fill empty space?"), + tr("Do you want to fill empty space?"), + QMessageBox::No | QMessageBox::Yes, QMessageBox::Yes); - if(button == QMessageBox::Yes || button == QMessageBox::No) + if(b != QMessageBox::Yes && b != QMessageBox::No) { - std::map poses = _ui->widget_mapVisibility->getVisiblePoses(); + return; + } + gridUnknownSpaceFilled = b == QMessageBox::Yes; - _initProgressDialog->setAutoClose(true, 1); - _initProgressDialog->resetProgress(); - _initProgressDialog->show(); - _initProgressDialog->setMaximumSteps(int(poses.size())*2+1); - - std::map::Ptr> clouds; - if(button == QMessageBox::Yes) + std::map::Ptr > scans; + std::map posesIn = _ui->widget_mapVisibility->getVisiblePoses(); + std::map poses; + for(std::map::const_iterator iter = posesIn.begin(); iter!=posesIn.end(); ++iter) + { + if(_depths2DMap.contains(iter->first)) { - pcl::PointCloud::Ptr cloud = this->createAssembledCloud(poses); - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (The cloud has %1 points, this " - "may take a while to process!)").arg(cloud->size()), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - if(button == QMessageBox::Yes) - { - pcl::PointCloud::Ptr cloudWithNormals; - _initProgressDialog->appendText(tr("Smoothing the surface using Moving Least Squares (MLS) algorithm... " - "[search radius=%1m]").arg(_preferencesDialog->getMeshSmoothingRadius(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); + cv::Mat depth2d = util3d::uncompressData(_depths2DMap.value(iter->first)); + scans.insert(std::make_pair(iter->first, util3d::depth2DToPointCloud(depth2d))); + poses.insert(*iter); + } + } - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(1)); - cloud->clear(); - pcl::copyPointCloud(*cloudWithNormals, *cloud); + // create the map + float xMin=0.0f, yMin=0.0f; + cv::Mat pixels = util3d::create2DMap(poses, scans, gridCellSize, gridUnknownSpaceFilled, xMin, yMin); + + if(!pixels.empty()) + { + cv::Mat map8U(pixels.rows, pixels.cols, CV_8U); + //convert to gray scaled map + for (int i = 0; i < pixels.rows; ++i) + { + for (int j = 0; j < pixels.cols; ++j) + { + char v = pixels.at(i, j); + unsigned char gray; + if(v == 0) + { + gray = 178; } - clouds.insert(std::make_pair(0, cloud)); + else if(v == 100) + { + gray = 0; + } + else // -1 + { + gray = 89; + } + map8U.at(i, j) = gray; } } + QImage image = uCvMat2QImage(map8U, false); + + QString path = QFileDialog::getSaveFileName(this, tr("Save to ..."), "grid.png", tr("Image (*.bmp *.png)")); + if(!path.isEmpty()) + { + QPixmap::fromImage(image.mirrored(false, true).transformed(QTransform().rotate(-90))).save(path); + } + } +} + +void MainWindow::exportPointClouds() +{ + std::map::Ptr> clouds; + std::map meshes; + + if(getExportedClouds(clouds, meshes, true)) + { + if(meshes.size()) + { + saveMeshes(meshes); + } else { - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (This " - "may take a while to process!)"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - clouds = this->createPointClouds(poses, button == QMessageBox::Yes); - } + saveClouds(clouds); } - savePointClouds(clouds); _initProgressDialog->setValue(_initProgressDialog->maximumSteps()); } } -void MainWindow::saveMeshes() +void MainWindow::viewClouds() { - int button = QMessageBox::question(this, - tr("One or multiple files?"), - tr("Merge all clouds together before surface reconstruction?\n" - " Yes: Output a single mesh for the merged clouds.\n" - " No: Output a mesh for each cloud." - "\n\nNote that all cloud generation parameters [decimation=%1, voxel=%2m, max depth=%3m] can be found in " - "Preferences -> GUI -> 3D Rendering under Exporting column.") - .arg(_preferencesDialog->getCloudDecimation(2)) - .arg(_preferencesDialog->getCloudVoxelSize(2)) - .arg(_preferencesDialog->getCloudMaxDepth(2)), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::Yes); + std::map::Ptr> clouds; + std::map meshes; - if(button == QMessageBox::Yes || button == QMessageBox::No) + if(getExportedClouds(clouds, meshes, false)) { - std::map poses = _ui->widget_mapVisibility->getVisiblePoses(); - - _initProgressDialog->setAutoClose(true, 1); - _initProgressDialog->resetProgress(); - _initProgressDialog->show(); - _initProgressDialog->setMaximumSteps(int(poses.size())*2+1); - - std::map meshes; - if(button == QMessageBox::Yes) + QWidget * window = new QWidget(this, Qt::Window); + window->setAttribute(Qt::WA_DeleteOnClose); + window->setWindowFlags(Qt::Dialog); + if(meshes.size()) { - pcl::PointCloud::Ptr cloud = this->createAssembledCloud(poses); - _initProgressDialog->appendText(tr("Meshing the assembled cloud (%1 points)...").arg(cloud->size())); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - pcl::PointCloud::Ptr cloudWithNormals; - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (The cloud has %1 points, this " - "may take a while to process!)").arg(cloud->size()), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - if(button == QMessageBox::Yes) - { - _initProgressDialog->appendText(tr("Smoothing the surface using Moving Least Squares (MLS) algorithm... " - "[search radius=%1m]").arg(_preferencesDialog->getMeshSmoothingRadius(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(1)); - } - else - { - _initProgressDialog->appendText(tr("Computing surface normals (without smoothing)... " - "[K neighbors=%1]").arg(_preferencesDialog->getMeshNormalKSearch(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch(1)); - } - - _initProgressDialog->appendText(tr("Greedy projection triangulation... [radius=%1m]").arg(_preferencesDialog->getMeshGP3Radius(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - pcl::PolygonMesh::Ptr mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius(1)); - meshes.insert(std::make_pair(0, mesh)); - } + window->setWindowTitle(tr("Meshes (%1 nodes)").arg(meshes.size())); } else { - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (This " - "may take a while to process!)"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - meshes = this->createMeshes(poses, button == QMessageBox::Yes); - } - } - saveMeshes(meshes); - _initProgressDialog->setValue(_initProgressDialog->maximumSteps()); - } -} - - - -void MainWindow::viewPointClouds() -{ - int button = QMessageBox::question(this, - tr("One or multiple clouds?"), - tr("Merge all clouds together?" - "\n\nNote that all cloud generation parameters [decimation=%1, voxel=%2m, max depth=%3m] can be found in " - "Preferences -> GUI -> 3D Rendering under High res view column.") - .arg(_preferencesDialog->getCloudDecimation(2)) - .arg(_preferencesDialog->getCloudVoxelSize(2)) - .arg(_preferencesDialog->getCloudMaxDepth(2)), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::Yes); - - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - std::map poses = _ui->widget_mapVisibility->getVisiblePoses(); - - _initProgressDialog->setAutoClose(true, 1); - _initProgressDialog->resetProgress(); - _initProgressDialog->show(); - _initProgressDialog->setMaximumSteps(int(poses.size())+1); - - std::map::Ptr> clouds; - if(button == QMessageBox::Yes) - { - pcl::PointCloud::Ptr cloud = this->createAssembledCloud(poses); - - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (The cloud has %1 points, this " - "may take a while to process!)").arg(cloud->size()), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - if(button == QMessageBox::Yes) - { - pcl::PointCloud::Ptr cloudWithNormals; - _initProgressDialog->appendText(tr("Smoothing the surface using Moving Least Squares (MLS) algorithm... " - "[search radius=%1m]").arg(_preferencesDialog->getMeshSmoothingRadius(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(1)); - cloud->clear(); - pcl::copyPointCloud(*cloudWithNormals, *cloud); - } - - clouds.insert(std::make_pair(0, cloud)); - } - } - else - { - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (This " - "may take a while to process!)"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - clouds = this->createPointClouds(poses, button == QMessageBox::Yes); - } - } - - if(clouds.size()) - { - QWidget * window = new QWidget(this, Qt::Window); - window->setAttribute(Qt::WA_DeleteOnClose); - window->setWindowFlags(Qt::Dialog); window->setWindowTitle(tr("Clouds (%1 nodes)").arg(clouds.size())); - window->setMinimumWidth(800); - window->setMinimumHeight(600); + } + window->setMinimumWidth(800); + window->setMinimumHeight(600); - CloudViewer * viewer = new CloudViewer(window); - viewer->setCameraLockZ(false); + CloudViewer * viewer = new CloudViewer(window); + viewer->setCameraLockZ(false); - QVBoxLayout *layout = new QVBoxLayout(); - layout->addWidget(viewer); - window->setLayout(layout); + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(viewer); + window->setLayout(layout); - window->show(); + window->show(); - uSleep(500); + uSleep(500); + if(meshes.size()) + { + for(std::map::iterator iter = meshes.begin(); iter!=meshes.end(); ++iter) + { + _initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)...").arg(iter->first).arg(iter->second->polygons.size())); + _initProgressDialog->incrementStep(); + pcl::PointCloud::Ptr cloud(new pcl::PointCloud); + pcl::fromPCLPointCloud2(iter->second->cloud, *cloud); + viewer->addCloudMesh(uFormat("mesh%d",iter->first), cloud, iter->second->polygons, iter->first>0?_currentPosesMap.at(iter->first):Transform::getIdentity()); + _initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)... done.").arg(iter->first).arg(iter->second->polygons.size())); + QApplication::processEvents(); + } + } + else if(clouds.size()) + { for(std::map::Ptr>::iterator iter = clouds.begin(); iter!=clouds.end(); ++iter) { _initProgressDialog->appendText(tr("Viewing the cloud %1 (%2 points)...").arg(iter->first).arg(iter->second->size())); @@ -3122,125 +3022,89 @@ void MainWindow::viewPointClouds() } } -void MainWindow::viewMeshes() +bool MainWindow::getExportedClouds( + std::map::Ptr> & clouds, + std::map & meshes, + bool toSave) { - int button = QMessageBox::question(this, - tr("One or multiple meshes?"), - tr("Merge all clouds together before surface reconstruction?\n" - " Yes: Output a single mesh for the merged clouds.\n" - " No: Output a mesh for each cloud." - "\n\nNote that all cloud generation parameters [decimation=%1, voxel=%2m, max depth=%3m] can be found in " - "Preferences -> GUI -> 3D Rendering under High res view column.") - .arg(_preferencesDialog->getCloudDecimation(2)) - .arg(_preferencesDialog->getCloudVoxelSize(2)) - .arg(_preferencesDialog->getCloudMaxDepth(2)), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::Yes); + ExportCloudsDialog * dialog = new ExportCloudsDialog(this, toSave); - if(button == QMessageBox::Yes || button == QMessageBox::No) + if(dialog->exec() == QDialog::Accepted) { std::map poses = _ui->widget_mapVisibility->getVisiblePoses(); _initProgressDialog->setAutoClose(true, 1); _initProgressDialog->resetProgress(); _initProgressDialog->show(); - _initProgressDialog->setMaximumSteps(int(poses.size())+1); + int mul = dialog->getMesh()&&!dialog->getGenerate()?3:dialog->getMLS()&&!dialog->getGenerate()?2:1; + _initProgressDialog->setMaximumSteps(int(poses.size())*mul+1); - std::map meshes; - if(button == QMessageBox::Yes) + if(dialog->getAssemble()) { - pcl::PointCloud::Ptr cloud = this->createAssembledCloud(poses); - _initProgressDialog->appendText(tr("Meshing the assembled cloud (%1 points)...").arg(cloud->size())); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); + pcl::PointCloud::Ptr cloud = this->getAssembledCloud( + poses, + dialog->getAssembleVoxel(), + dialog->getGenerate(), + dialog->getGenerateDecimation(), + dialog->getGenerateVoxel(), + dialog->getGenerateMaxDepth()); - pcl::PointCloud::Ptr cloudWithNormals; - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (The cloud has %1 points, this " - "may take a while to process!)").arg(cloud->size()), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - if(button == QMessageBox::Yes) - { - _initProgressDialog->appendText(tr("Smoothing the surface using Moving Least Squares (MLS) algorithm... " - "[search radius=%1m]").arg(_preferencesDialog->getMeshSmoothingRadius(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(1)); - } - else - { - _initProgressDialog->appendText(tr("Computing surface normals (without smoothing)... " - "[K neighbors=%1]").arg(_preferencesDialog->getMeshNormalKSearch(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch(1)); - } - - _initProgressDialog->appendText(tr("Greedy projection triangulation... [radius=%1m]").arg(_preferencesDialog->getMeshGP3Radius(1))); - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - - pcl::PolygonMesh::Ptr mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius(1)); - meshes.insert(std::make_pair(0, mesh)); - } + clouds.insert(std::make_pair(0, cloud)); } else { - button = QMessageBox::question( - this, - tr("Smoothing..."), - tr("Would you want to smooth the surface using Moving " - "Least Squares algorithm? (This " - "may take a while to process!)"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::No); - if(button == QMessageBox::Yes || button == QMessageBox::No) - { - meshes = this->createMeshes(poses, button == QMessageBox::Yes); - } + clouds = this->getClouds( + poses, + dialog->getGenerate(), + dialog->getGenerateDecimation(), + dialog->getGenerateVoxel(), + dialog->getGenerateMaxDepth()); } - if(meshes.size()) + if(dialog->getMLS() || dialog->getMesh()) { - QWidget * window = new QWidget(this, Qt::Window); - window->setAttribute(Qt::WA_DeleteOnClose); - window->setWindowTitle(tr("Meshes (%1 nodes)").arg(meshes.size())); - window->setMinimumWidth(800); - window->setMinimumHeight(600); - - CloudViewer * viewer = new CloudViewer(window); - viewer->setCameraLockZ(false); - - QVBoxLayout *layout = new QVBoxLayout(); - layout->addWidget(viewer); - window->setLayout(layout); - - window->show(); - - uSleep(500); - - for(std::map::iterator iter = meshes.begin(); iter!=meshes.end(); ++iter) + for(std::map::Ptr>::iterator iter=clouds.begin(); + iter!= clouds.end(); + ++iter) { - _initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)...").arg(iter->first).arg(iter->second->polygons.size())); - _initProgressDialog->incrementStep(); - pcl::PointCloud::Ptr cloud(new pcl::PointCloud); - pcl::fromPCLPointCloud2(iter->second->cloud, *cloud); - viewer->addCloudMesh(uFormat("mesh%d",iter->first), cloud, iter->second->polygons, iter->first>0?_currentPosesMap.at(iter->first):Transform::getIdentity()); - _initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)... done.").arg(iter->first).arg(iter->second->polygons.size())); - QApplication::processEvents(); + pcl::PointCloud::Ptr cloudWithNormals; + if(dialog->getMLS()) + { + _initProgressDialog->appendText(tr("Smoothing the surface of cloud %1 using Moving Least Squares (MLS) algorithm... " + "[search radius=%2m]").arg(iter->first).arg(dialog->getMLSRadius())); + _initProgressDialog->incrementStep(); + QApplication::processEvents(); + + cloudWithNormals = util3d::computeNormalsSmoothed(iter->second, (float)dialog->getMLSRadius()); + + iter->second->clear(); + pcl::copyPointCloud(*cloudWithNormals, *iter->second); + } + else if(dialog->getMesh()) + { + _initProgressDialog->appendText(tr("Computing surface normals of cloud %1 (without smoothing)... " + "[K neighbors=%2]").arg(iter->first).arg(dialog->getMeshNormalKSearch())); + _initProgressDialog->incrementStep(); + QApplication::processEvents(); + + cloudWithNormals = util3d::computeNormals(iter->second, dialog->getMeshNormalKSearch()); + } + + if(dialog->getMesh()) + { + _initProgressDialog->appendText(tr("Greedy projection triangulation... [radius=%1m]").arg(dialog->getMeshGp3Radius())); + _initProgressDialog->incrementStep(); + QApplication::processEvents(); + + pcl::PolygonMesh::Ptr mesh = util3d::createMesh(cloudWithNormals, dialog->getMeshGp3Radius()); + meshes.insert(std::make_pair(iter->first, mesh)); + } } } - _initProgressDialog->setValue(_initProgressDialog->maximumSteps()); + return true; } + return false; } void MainWindow::resetOdometry() @@ -3301,11 +3165,11 @@ void MainWindow::dataRecorder() //END ACTIONS -void MainWindow::savePointClouds(const std::map::Ptr> & clouds) +void MainWindow::saveClouds(const std::map::Ptr> & clouds) { if(clouds.size() == 1) { - QString path = QFileDialog::getSaveFileName(this, tr("Save to ..."), "cloud.ply", tr("Point cloud data (*.ply *.pcd *.vtk)")); + QString path = QFileDialog::getSaveFileName(this, tr("Save to ..."), "cloud.ply", tr("Point cloud data (*.ply *.pcd)")); if(!path.isEmpty()) { if(clouds.begin()->second->size()) @@ -3321,12 +3185,6 @@ void MainWindow::savePointClouds(const std::mapsecond) == 0; } - else if(QFileInfo(path).suffix() == "vtk") - { - pcl::PCLPointCloud2 pt2; - pcl::toPCLPointCloud2(*clouds.begin()->second, pt2); - success = pcl::io::saveVTKFile(path.toStdString(), pt2) == 0; - } else if(QFileInfo(path).suffix() == "") { //use ply by default @@ -3335,7 +3193,7 @@ void MainWindow::savePointClouds(const std::mapgetWorkingDirectory(), 0); + QString path = QFileDialog::getExistingDirectory(this, tr("Save to (*.ply *.pcd)..."), _preferencesDialog->getWorkingDirectory(), 0); if(!path.isEmpty()) { bool ok = false; QStringList items; items.push_back("ply"); items.push_back("pcd"); - items.push_back("vtk"); QString suffix = QInputDialog::getItem(this, tr("File format"), tr("Which format?"), items, 0, false, &ok); if(ok) { - for(std::map::Ptr >::const_iterator iter=clouds.begin(); iter!=clouds.end(); ++iter) - { - if(iter->second->size()) - { - pcl::PointCloud::Ptr transformedCloud; - transformedCloud = util3d::transformPointCloud(iter->second, _currentPosesMap.at(iter->first)); + QString prefix = QInputDialog::getText(this, tr("File prefix"), tr("Prefix:"), QLineEdit::Normal, "cloud", &ok); - QString pathFile = path+QDir::separator()+QString("cloud%1.%2").arg(iter->first).arg(suffix); - bool success =false; - if(suffix == "pcd") - { - success = pcl::io::savePCDFile(pathFile.toStdString(), *transformedCloud) == 0; - } - else if(suffix == "ply") - { - success = pcl::io::savePLYFile(pathFile.toStdString(), *transformedCloud) == 0; - } - else if(suffix == "vtk") - { - pcl::PCLPointCloud2 pt2; - pcl::toPCLPointCloud2(*transformedCloud, pt2); - success = pcl::io::saveVTKFile(pathFile.toStdString(), pt2) == 0; - } - else - { - UFATAL("Extension not recognized! (%s)", suffix.toStdString().c_str()); - } - if(success) - { - _initProgressDialog->appendText(tr("Saved cloud %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile)); - } - else - { - _initProgressDialog->appendText(tr("Failed saving cloud %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile)); - } - } - else + if(ok) + { + for(std::map::Ptr >::const_iterator iter=clouds.begin(); iter!=clouds.end(); ++iter) { - _initProgressDialog->appendText(tr("Cloud %1 is empty!").arg(iter->first)); + if(iter->second->size()) + { + pcl::PointCloud::Ptr transformedCloud; + transformedCloud = util3d::transformPointCloud(iter->second, _currentPosesMap.at(iter->first)); + + QString pathFile = path+QDir::separator()+QString("%1%2.%3").arg(prefix).arg(iter->first).arg(suffix); + bool success =false; + if(suffix == "pcd") + { + success = pcl::io::savePCDFile(pathFile.toStdString(), *transformedCloud) == 0; + } + else if(suffix == "ply") + { + success = pcl::io::savePLYFile(pathFile.toStdString(), *transformedCloud) == 0; + } + else + { + UFATAL("Extension not recognized! (%s)", suffix.toStdString().c_str()); + } + if(success) + { + _initProgressDialog->appendText(tr("Saved cloud %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile)); + } + else + { + _initProgressDialog->appendText(tr("Failed saving cloud %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile)); + } + } + else + { + _initProgressDialog->appendText(tr("Cloud %1 is empty!").arg(iter->first)); + } + _initProgressDialog->incrementStep(); + QApplication::processEvents(); } - _initProgressDialog->incrementStep(); - QApplication::processEvents(); } } } @@ -3421,7 +3277,7 @@ void MainWindow::saveMeshes(const std::map & meshes) { if(meshes.size() == 1) { - QString path = QFileDialog::getSaveFileName(this, tr("Save to ..."), "mesh.ply", tr("Mesh (*.ply *.vtk)")); + QString path = QFileDialog::getSaveFileName(this, tr("Save to ..."), "mesh.ply", tr("Mesh (*.ply)")); if(!path.isEmpty()) { if(meshes.begin()->second->polygons.size()) @@ -3433,11 +3289,6 @@ void MainWindow::saveMeshes(const std::map & meshes) { success = pcl::io::savePLYFile(path.toStdString(), *meshes.begin()->second) == 0; } - else if(QFileInfo(path).suffix() == "vtk") - { - success = pcl::io::saveVTKFile(path.toStdString(), *meshes.begin()->second) == 0; - - } else if(QFileInfo(path).suffix() == "") { //default ply @@ -3446,7 +3297,7 @@ void MainWindow::saveMeshes(const std::map & meshes) } else { - UERROR("Extension not recognized! (%s) Should be one of (*.ply *.vtk).", QFileInfo(path).suffix().toStdString().c_str()); + UERROR("Extension not recognized! (%s) Should be (*.ply).", QFileInfo(path).suffix().toStdString().c_str()); } if(success) { @@ -3468,14 +3319,12 @@ void MainWindow::saveMeshes(const std::map & meshes) } else if(meshes.size()) { - QString path = QFileDialog::getExistingDirectory(this, tr("Save to (*.ply, *.vtk)..."), _preferencesDialog->getWorkingDirectory(), 0); + QString path = QFileDialog::getExistingDirectory(this, tr("Save to (*.ply)..."), _preferencesDialog->getWorkingDirectory(), 0); if(!path.isEmpty()) { bool ok = false; - QStringList items; - items.push_back("ply"); - items.push_back("vtk"); - QString suffix = QInputDialog::getItem(this, tr("File format"), tr("Which format?"), items, 0, false, &ok); + QString prefix = QInputDialog::getText(this, tr("File prefix"), tr("Prefix:"), QLineEdit::Normal, "mesh", &ok); + QString suffix = "ply"; if(ok) { @@ -3490,16 +3339,12 @@ void MainWindow::saveMeshes(const std::map & meshes) tmp = util3d::transformPointCloud(tmp, _currentPosesMap.at(iter->first)); pcl::toPCLPointCloud2(*tmp, mesh.cloud); - QString pathFile = path+QDir::separator()+QString("mesh%1.%2").arg(iter->first).arg(suffix); + QString pathFile = path+QDir::separator()+QString("%1%2.%3").arg(prefix).arg(iter->first).arg(suffix); bool success =false; if(suffix == "ply") { success = pcl::io::savePLYFile(pathFile.toStdString(), mesh) == 0; } - else if(suffix == "vtk") - { - success = pcl::io::saveVTKFile(pathFile.toStdString(), mesh) == 0; - } else { UFATAL("Extension not recognized! (%s)", suffix.toStdString().c_str()); @@ -3578,7 +3423,13 @@ pcl::PointCloud::Ptr MainWindow::createCloud( return cloud; } -pcl::PointCloud::Ptr MainWindow::createAssembledCloud(const std::map & poses) const +pcl::PointCloud::Ptr MainWindow::getAssembledCloud( + const std::map & poses, + float assembledVoxelSize, + bool regenerateClouds, + int regenerateDecimation, + float regenerateVoxelSize, + float regenerateMaxDepth) const { pcl::PointCloud::Ptr assembledCloud(new pcl::PointCloud); int i=0; @@ -3591,23 +3442,24 @@ pcl::PointCloud::Ptr MainWindow::createAssembledCloud(const st if(_imagesMap.contains(iter->first) && _depthsMap.contains(iter->first)) { pcl::PointCloud::Ptr cloud; - cloud = createCloud(iter->first, - util3d::uncompressImage(_imagesMap.value(iter->first)), - util3d::uncompressImage(_depthsMap.value(iter->first)), - _depthFxsMap.value(iter->first), - _depthFysMap.value(iter->first), - _depthCxsMap.value(iter->first), - _depthCysMap.value(iter->first), - _localTransformsMap.value(iter->first), - iter->second, - _preferencesDialog->getCloudVoxelSize(2), - _preferencesDialog->getCloudDecimation(2), - _preferencesDialog->getCloudMaxDepth(2)); - - if(cloud->size() && _preferencesDialog->getCloudVoxelSize(2)) + if(regenerateClouds) { - UDEBUG("Voxelize the cloud %d (%d points, voxel %f m)", iter->first, (int)cloud->size(), _preferencesDialog->getCloudVoxelSize(2)); - cloud = util3d::voxelize(cloud, _preferencesDialog->getCloudVoxelSize(2)); + cloud = createCloud(iter->first, + util3d::uncompressImage(_imagesMap.value(iter->first)), + util3d::uncompressImage(_depthsMap.value(iter->first)), + _depthFxsMap.value(iter->first), + _depthFysMap.value(iter->first), + _depthCxsMap.value(iter->first), + _depthCysMap.value(iter->first), + _localTransformsMap.value(iter->first), + iter->second, + regenerateVoxelSize, + regenerateDecimation, + regenerateMaxDepth); + } + else if(_createdClouds.contains(iter->first)) + { + cloud = util3d::transformPointCloud(_createdClouds.value(iter->first), iter->second); } if(cloud->size()) @@ -3634,9 +3486,9 @@ pcl::PointCloud::Ptr MainWindow::createAssembledCloud(const st if(count % 100 == 0) { - if(assembledCloud->size() && _preferencesDialog->getCloudVoxelSize(2)) + if(assembledCloud->size() && assembledVoxelSize) { - assembledCloud = util3d::voxelize(assembledCloud, _preferencesDialog->getCloudVoxelSize(2)); + assembledCloud = util3d::voxelize(assembledCloud, assembledVoxelSize); } } } @@ -3648,17 +3500,20 @@ pcl::PointCloud::Ptr MainWindow::createAssembledCloud(const st QApplication::processEvents(); } - if(assembledCloud->size() && _preferencesDialog->getCloudVoxelSize(2)) + if(assembledCloud->size() && assembledVoxelSize) { - assembledCloud = util3d::voxelize(assembledCloud, _preferencesDialog->getCloudVoxelSize(2)); + assembledCloud = util3d::voxelize(assembledCloud, assembledVoxelSize); } return assembledCloud; } -std::map::Ptr > MainWindow::createPointClouds( +std::map::Ptr > MainWindow::getClouds( const std::map & poses, - bool applyMLS) const + bool regenerateClouds, + int regenerateDecimation, + float regenerateVoxelSize, + float regenerateMaxDepth) const { std::map::Ptr> clouds; int i=0; @@ -3670,35 +3525,28 @@ std::map::Ptr > MainWindow::createPointCl if(_imagesMap.contains(iter->first) && _depthsMap.contains(iter->first)) { pcl::PointCloud::Ptr cloud; - cloud = createCloud(iter->first, - util3d::uncompressImage(_imagesMap.value(iter->first)), - util3d::uncompressImage(_depthsMap.value(iter->first)), - _depthFxsMap.value(iter->first), - _depthFysMap.value(iter->first), - _depthCxsMap.value(iter->first), - _depthCysMap.value(iter->first), - _localTransformsMap.value(iter->first), - Transform::getIdentity(), - _preferencesDialog->getCloudVoxelSize(2), - _preferencesDialog->getCloudDecimation(2), - _preferencesDialog->getCloudMaxDepth(2)); - - if(cloud->size() && _preferencesDialog->getCloudVoxelSize(2)) + if(regenerateClouds) { - UDEBUG("Voxelize the cloud of %d points (%f m)", (int)cloud->size(), _preferencesDialog->getCloudVoxelSize(2)); - cloud = util3d::voxelize(cloud, _preferencesDialog->getCloudVoxelSize(2)); + cloud = createCloud(iter->first, + util3d::uncompressImage(_imagesMap.value(iter->first)), + util3d::uncompressImage(_depthsMap.value(iter->first)), + _depthFxsMap.value(iter->first), + _depthFysMap.value(iter->first), + _depthCxsMap.value(iter->first), + _depthCysMap.value(iter->first), + _localTransformsMap.value(iter->first), + Transform::getIdentity(), + regenerateVoxelSize, + regenerateDecimation, + regenerateMaxDepth); + } + else if(_createdClouds.contains(iter->first)) + { + cloud = _createdClouds.value(iter->first); } if(cloud->size()) { - if(applyMLS) - { - pcl::PointCloud::Ptr cloudWithNormals; - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(1)); - cloud->clear(); - pcl::copyPointCloud(*cloudWithNormals, *cloud); - } - clouds.insert(std::make_pair(iter->first, cloud)); inserted = true; } @@ -3728,83 +3576,6 @@ std::map::Ptr > MainWindow::createPointCl return clouds; } -std::map MainWindow::createMeshes(const std::map & poses, bool applyMLS) const -{ - std::map meshes; - int i=0; - for(std::map::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter) - { - bool inserted = false; - if(!iter->second.isNull()) - { - if(_imagesMap.contains(iter->first) && _depthsMap.contains(iter->first)) - { - pcl::PointCloud::Ptr cloud; - cloud = createCloud(iter->first, - util3d::uncompressImage(_imagesMap.value(iter->first)), - util3d::uncompressImage(_depthsMap.value(iter->first)), - _depthFxsMap.value(iter->first), - _depthFysMap.value(iter->first), - _depthCxsMap.value(iter->first), - _depthCysMap.value(iter->first), - _localTransformsMap.value(iter->first), - Transform::getIdentity(), - _preferencesDialog->getCloudVoxelSize(2), - _preferencesDialog->getCloudDecimation(2), - _preferencesDialog->getCloudMaxDepth(2)); - - if(cloud->size() && _preferencesDialog->getCloudVoxelSize(2)) - { - UDEBUG("Voxelize the cloud of %d points (%f m)", (int)cloud->size(), _preferencesDialog->getCloudVoxelSize(2)); - cloud = util3d::voxelize(cloud, _preferencesDialog->getCloudVoxelSize(2)); - } - - pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh); - if(cloud->size()) - { - pcl::PointCloud::Ptr cloudWithNormals; - if(applyMLS) - { - cloudWithNormals = util3d::computeNormalsSmoothed(cloud, (float)_preferencesDialog->getMeshSmoothingRadius(1)); - } - else - { - cloudWithNormals = util3d::computeNormals(cloud, _preferencesDialog->getMeshNormalKSearch(1)); - } - mesh = util3d::createMesh(cloudWithNormals, _preferencesDialog->getMeshGP3Radius(1)); - } - - if(mesh->polygons.size()) - { - meshes.insert(std::make_pair(iter->first, mesh)); - inserted = true; - } - } - else - { - UERROR("Cloud %d not found?!?", iter->first); - } - } - else - { - UERROR("transform is null!?"); - } - - if(inserted) - { - _initProgressDialog->appendText(tr("Generated mesh %1 (%2/%3).").arg(iter->first).arg(++i).arg(poses.size())); - } - else - { - _initProgressDialog->appendText(tr("Ignored mesh %1 (%2/%3).").arg(iter->first).arg(++i).arg(poses.size())); - } - _initProgressDialog->incrementStep(); - QApplication::processEvents(); - } - - return meshes; -} - // STATES // in monitoring state, only some actions are enabled diff --git a/guilib/src/PreferencesDialog.cpp b/guilib/src/PreferencesDialog.cpp index eca602b7..f01d4404 100644 --- a/guilib/src/PreferencesDialog.cpp +++ b/guilib/src/PreferencesDialog.cpp @@ -121,25 +121,21 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : connect(_ui->horizontalSlider_keypointsOpacity, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteGeneralPanel())); // Cloud rendering panel - _3dRenderingShowClouds.resize(3); + _3dRenderingShowClouds.resize(2); _3dRenderingShowClouds[0] = _ui->checkBox_showClouds; _3dRenderingShowClouds[1] = _ui->checkBox_showOdomClouds; - _3dRenderingShowClouds[2] = _ui->checkBox_showSaveClouds; - _3dRenderingVoxelSize.resize(3); + _3dRenderingVoxelSize.resize(2); _3dRenderingVoxelSize[0] = _ui->doubleSpinBox_voxelSize; _3dRenderingVoxelSize[1] = _ui->doubleSpinBox_voxelSize_odom; - _3dRenderingVoxelSize[2] = _ui->doubleSpinBox_voxelSize_save; - _3dRenderingDecimation.resize(3); + _3dRenderingDecimation.resize(2); _3dRenderingDecimation[0] = _ui->spinBox_decimation; _3dRenderingDecimation[1] = _ui->spinBox_decimation_odom; - _3dRenderingDecimation[2] = _ui->spinBox_decimation_save; - _3dRenderingMaxDepth.resize(3); + _3dRenderingMaxDepth.resize(2); _3dRenderingMaxDepth[0] = _ui->doubleSpinBox_maxDepth; _3dRenderingMaxDepth[1] = _ui->doubleSpinBox_maxDepth_odom; - _3dRenderingMaxDepth[2] = _ui->doubleSpinBox_maxDepth_save; _3dRenderingOpacity.resize(2); _3dRenderingOpacity[0] = _ui->doubleSpinBox_opacity; @@ -149,10 +145,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : _3dRenderingPtSize[0] = _ui->spinBox_ptsize; _3dRenderingPtSize[1] = _ui->spinBox_ptsize_odom; - _3dRenderingShowScans.resize(3); + _3dRenderingShowScans.resize(2); _3dRenderingShowScans[0] = _ui->checkBox_showScans; _3dRenderingShowScans[1] = _ui->checkBox_showOdomScans; - _3dRenderingShowScans[2] = _ui->checkBox_showSaveScans; _3dRenderingOpacityScan.resize(2); _3dRenderingOpacityScan[0] = _ui->doubleSpinBox_opacity_scan; @@ -162,25 +157,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : _3dRenderingPtSizeScan[0] = _ui->spinBox_ptsize_scan; _3dRenderingPtSizeScan[1] = _ui->spinBox_ptsize_odom_scan; - _3dRenderingMeshing.resize(1); - _3dRenderingMeshing[0] = _ui->checkBox_meshing; - - _3dRenderingNormalKSearch.resize(2); - _3dRenderingNormalKSearch[0] = _ui->spinBox_normalKSearch; - _3dRenderingNormalKSearch[1] = _ui->spinBox_normalKSearch_save; - - _3dRenderingGP3Radius.resize(2); - _3dRenderingGP3Radius[0] = _ui->doubleSpinBox_gp3Radius; - _3dRenderingGP3Radius[1] = _ui->doubleSpinBox_gp3Radius_save; - - _3dRenderingSmoothing.resize(2); - _3dRenderingSmoothing[0] = _ui->checkBox_mls; - - _3dRenderingSmoothingRadius.resize(2); - _3dRenderingSmoothingRadius[0] = _ui->doubleSpinBox_mlsRadius; - _3dRenderingSmoothingRadius[1] = _ui->doubleSpinBox_mlsRadius_save; - - for(int i=0; i<3; ++i) + for(int i=0; i<2; ++i) { connect(_3dRenderingShowClouds[i], SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_3dRenderingVoxelSize[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); @@ -188,24 +165,16 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) : connect(_3dRenderingMaxDepth[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_3dRenderingShowScans[i], SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); - if(i<2) - { - connect(_3dRenderingOpacity[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); - connect(_3dRenderingPtSize[i], SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); - connect(_3dRenderingOpacityScan[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); - connect(_3dRenderingPtSizeScan[i], SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); - - connect(_3dRenderingNormalKSearch[i], SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); - connect(_3dRenderingGP3Radius[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); - connect(_3dRenderingSmoothingRadius[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); - } - - if(i<1) - { - connect(_3dRenderingMeshing[i], SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); - connect(_3dRenderingSmoothing[i], SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); - } + connect(_3dRenderingOpacity[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); + connect(_3dRenderingPtSize[i], SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); + connect(_3dRenderingOpacityScan[i], SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); + connect(_3dRenderingPtSizeScan[i], SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); } + connect(_ui->checkBox_meshing, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); + connect(_ui->doubleSpinBox_gp3Radius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); + connect(_ui->spinBox_normalKSearch, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); + connect(_ui->checkBox_mls, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteCloudRenderingPanel())); + connect(_ui->doubleSpinBox_mlsRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_ui->groupBox_poseFiltering, SIGNAL(clicked(bool)), this, SLOT(makeObsoleteCloudRenderingPanel())); connect(_ui->doubleSpinBox_cloudFilterRadius, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteCloudRenderingPanel())); @@ -751,7 +720,7 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox) } else if(groupBox->objectName() == _ui->groupBox_cloudRendering1->objectName()) { - for(int i=0; i<3; ++i) + for(int i=0; i<2; ++i) { _3dRenderingShowClouds[i]->setChecked(true); _3dRenderingVoxelSize[i]->setValue(i==2?0.005:0.00); @@ -759,24 +728,16 @@ void PreferencesDialog::resetSettings(QGroupBox * groupBox) _3dRenderingMaxDepth[i]->setValue(i==1?0.0:4.0); _3dRenderingShowScans[i]->setChecked(true); - if(i<2) - { - _3dRenderingOpacity[i]->setValue(1.0); - _3dRenderingPtSize[i]->setValue(i==0?1:2); - _3dRenderingOpacityScan[i]->setValue(1.0); - _3dRenderingPtSizeScan[i]->setValue(1); - - _3dRenderingNormalKSearch[i]->setValue(20); - _3dRenderingGP3Radius[i]->setValue(0.04); - _3dRenderingSmoothingRadius[i]->setValue(0.04); - } - - if(i<1) - { - _3dRenderingMeshing[i]->setChecked(false); - _3dRenderingSmoothing[i]->setChecked(false); - } + _3dRenderingOpacity[i]->setValue(1.0); + _3dRenderingPtSize[i]->setValue(i==0?1:2); + _3dRenderingOpacityScan[i]->setValue(1.0); + _3dRenderingPtSizeScan[i]->setValue(1); } + _ui->checkBox_meshing->setChecked(false); + _ui->doubleSpinBox_gp3Radius->setValue(0.04); + _ui->spinBox_normalKSearch->setValue(20); + _ui->checkBox_mls->setChecked(false); + _ui->doubleSpinBox_mlsRadius->setValue(0.04); _ui->groupBox_poseFiltering->setChecked(false); _ui->doubleSpinBox_cloudFilterRadius->setValue(0.1); @@ -988,32 +949,24 @@ void PreferencesDialog::readGuiSettings(const QString & filePath) _ui->checkBox_beep->setChecked(settings.value("beep", _ui->checkBox_beep->isChecked()).toBool()); _ui->horizontalSlider_keypointsOpacity->setValue(settings.value("keypointsOpacity", _ui->horizontalSlider_keypointsOpacity->value()).toInt()); - for(int i=0; i<3; ++i) + for(int i=0; i<2; ++i) { - _3dRenderingShowClouds[i]->setChecked(settings.value(tr("showClouds%1").arg(i), _3dRenderingShowClouds[i]->isChecked()).toBool()); - _3dRenderingVoxelSize[i]->setValue(settings.value(tr("voxelSize%1").arg(i), _3dRenderingVoxelSize[i]->value()).toDouble()); - _3dRenderingDecimation[i]->setValue(settings.value(tr("decimation%1").arg(i), _3dRenderingDecimation[i]->value()).toInt()); - _3dRenderingMaxDepth[i]->setValue(settings.value(tr("maxDepth%1").arg(i), _3dRenderingMaxDepth[i]->value()).toDouble()); - _3dRenderingShowScans[i]->setChecked(settings.value(tr("showScans%1").arg(i), _3dRenderingShowScans[i]->isChecked()).toBool()); + _3dRenderingShowClouds[i]->setChecked(settings.value(QString("showClouds%1").arg(i), _3dRenderingShowClouds[i]->isChecked()).toBool()); + _3dRenderingVoxelSize[i]->setValue(settings.value(QString("voxelSize%1").arg(i), _3dRenderingVoxelSize[i]->value()).toDouble()); + _3dRenderingDecimation[i]->setValue(settings.value(QString("decimation%1").arg(i), _3dRenderingDecimation[i]->value()).toInt()); + _3dRenderingMaxDepth[i]->setValue(settings.value(QString("maxDepth%1").arg(i), _3dRenderingMaxDepth[i]->value()).toDouble()); + _3dRenderingShowScans[i]->setChecked(settings.value(QString("showScans%1").arg(i), _3dRenderingShowScans[i]->isChecked()).toBool()); - if(i<2) - { - _3dRenderingOpacity[i]->setValue(settings.value(tr("opacity%1").arg(i), _3dRenderingOpacity[i]->value()).toDouble()); - _3dRenderingPtSize[i]->setValue(settings.value(tr("ptSize%1").arg(i), _3dRenderingPtSize[i]->value()).toInt()); - _3dRenderingOpacityScan[i]->setValue(settings.value(tr("opacityScan%1").arg(i), _3dRenderingOpacityScan[i]->value()).toDouble()); - _3dRenderingPtSizeScan[i]->setValue(settings.value(tr("ptSizeScan%1").arg(i), _3dRenderingPtSizeScan[i]->value()).toInt()); - - _3dRenderingNormalKSearch[i]->setValue(settings.value(tr("meshNormalKSearch%1").arg(i), _3dRenderingNormalKSearch[i]->value()).toInt()); - _3dRenderingGP3Radius[i]->setValue(settings.value(tr("meshGP3Radius%1").arg(i), _3dRenderingGP3Radius[i]->value()).toDouble()); - _3dRenderingSmoothingRadius[i]->setValue(settings.value(tr("meshSmoothingRadius%1").arg(i), _3dRenderingSmoothingRadius[i]->value()).toDouble()); - } - - if(i<1) - { - _3dRenderingMeshing[i]->setChecked(settings.value(tr("meshing%1").arg(i), _3dRenderingMeshing[i]->isChecked()).toBool()); - _3dRenderingSmoothing[i]->setChecked(settings.value(tr("meshSmoothing%1").arg(i), _3dRenderingSmoothing[i]->isChecked()).toBool()); - } + _3dRenderingOpacity[i]->setValue(settings.value(QString("opacity%1").arg(i), _3dRenderingOpacity[i]->value()).toDouble()); + _3dRenderingPtSize[i]->setValue(settings.value(QString("ptSize%1").arg(i), _3dRenderingPtSize[i]->value()).toInt()); + _3dRenderingOpacityScan[i]->setValue(settings.value(QString("opacityScan%1").arg(i), _3dRenderingOpacityScan[i]->value()).toDouble()); + _3dRenderingPtSizeScan[i]->setValue(settings.value(QString("ptSizeScan%1").arg(i), _3dRenderingPtSizeScan[i]->value()).toInt()); } + _ui->checkBox_meshing->setChecked(settings.value("meshing", _ui->checkBox_meshing->isChecked()).toBool()); + _ui->doubleSpinBox_gp3Radius->setValue(settings.value("meshGP3Radius", _ui->doubleSpinBox_gp3Radius->value()).toDouble()); + _ui->spinBox_normalKSearch->setValue(settings.value("meshNormalKSearch", _ui->spinBox_normalKSearch->value()).toInt()); + _ui->checkBox_mls->setChecked(settings.value("meshSmoothing", _ui->checkBox_mls->isChecked()).toBool()); + _ui->doubleSpinBox_mlsRadius->setValue(settings.value("meshSmoothingRadius", _ui->doubleSpinBox_mlsRadius->value()).toDouble()); _ui->groupBox_poseFiltering->setChecked(settings.value("cloudFiltering", _ui->groupBox_poseFiltering->isChecked()).toBool()); _ui->doubleSpinBox_cloudFilterRadius->setValue(settings.value("cloudFilteringRadius", _ui->doubleSpinBox_cloudFilterRadius->value()).toDouble()); @@ -1202,32 +1155,25 @@ void PreferencesDialog::writeGuiSettings(const QString & filePath) settings.setValue("beep", _ui->checkBox_beep->isChecked()); settings.setValue("keypointsOpacity", _ui->horizontalSlider_keypointsOpacity->value()); - for(int i=0; i<3; ++i) + for(int i=0; i<2; ++i) { - settings.setValue(tr("showClouds%1").arg(i), _3dRenderingShowClouds[i]->isChecked()); - settings.setValue(tr("voxelSize%1").arg(i), _3dRenderingVoxelSize[i]->value()); - settings.setValue(tr("decimation%1").arg(i), _3dRenderingDecimation[i]->value()); - settings.setValue(tr("maxDepth%1").arg(i), _3dRenderingMaxDepth[i]->value()); - settings.setValue(tr("showScans%1").arg(i), _3dRenderingShowScans[i]->isChecked()); + settings.setValue(QString("showClouds%1").arg(i), _3dRenderingShowClouds[i]->isChecked()); + settings.setValue(QString("voxelSize%1").arg(i), _3dRenderingVoxelSize[i]->value()); + settings.setValue(QString("decimation%1").arg(i), _3dRenderingDecimation[i]->value()); + settings.setValue(QString("maxDepth%1").arg(i), _3dRenderingMaxDepth[i]->value()); + settings.setValue(QString("showScans%1").arg(i), _3dRenderingShowScans[i]->isChecked()); - if(i<2) - { - settings.setValue(tr("opacity%1").arg(i), _3dRenderingOpacity[i]->value()); - settings.setValue(tr("ptSize%1").arg(i), _3dRenderingPtSize[i]->value()); - settings.setValue(tr("opacityScan%1").arg(i), _3dRenderingOpacityScan[i]->value()); - settings.setValue(tr("ptSizeScan%1").arg(i), _3dRenderingPtSizeScan[i]->value()); - - settings.setValue(tr("meshNormalKSearch%1").arg(i), _3dRenderingNormalKSearch[i]->value()); - settings.setValue(tr("meshGP3Radius%1").arg(i), _3dRenderingGP3Radius[i]->value()); - settings.setValue(tr("meshSmoothingRadius%1").arg(i), _3dRenderingSmoothingRadius[i]->value()); - } - - if(i<1) - { - settings.setValue(tr("meshing%1").arg(i), _3dRenderingMeshing[i]->isChecked()); - settings.setValue(tr("meshSmoothing%1").arg(i), _3dRenderingSmoothing[i]->isChecked()); - } + settings.setValue(QString("opacity%1").arg(i), _3dRenderingOpacity[i]->value()); + settings.setValue(QString("ptSize%1").arg(i), _3dRenderingPtSize[i]->value()); + settings.setValue(QString("opacityScan%1").arg(i), _3dRenderingOpacityScan[i]->value()); + settings.setValue(QString("ptSizeScan%1").arg(i), _3dRenderingPtSizeScan[i]->value()); } + settings.setValue("meshing", _ui->checkBox_meshing->isChecked()); + settings.setValue("meshGP3Radius", _ui->doubleSpinBox_gp3Radius->value()); + settings.setValue("meshNormalKSearch", _ui->spinBox_normalKSearch->value()); + settings.setValue("meshSmoothing", _ui->checkBox_mls->isChecked()); + settings.setValue("meshSmoothingRadius", _ui->doubleSpinBox_mlsRadius->value()); + settings.setValue("cloudFiltering", _ui->groupBox_poseFiltering->isChecked()); settings.setValue("cloudFilteringRadius", _ui->doubleSpinBox_cloudFilterRadius->value()); settings.setValue("cloudFilteringAngle", _ui->doubleSpinBox_cloudFilterAngle->value()); @@ -2445,27 +2391,26 @@ int PreferencesDialog::getOdomQualityWarnThr() const bool PreferencesDialog::isCloudsShown(int index) const { - UASSERT(index >= 0 && index <= 2); + UASSERT(index >= 0 && index <= 1); return _3dRenderingShowClouds[index]->isChecked(); } -bool PreferencesDialog::isCloudMeshing(int index) const +bool PreferencesDialog::isCloudMeshing() const { - UASSERT(index == 0); - return _3dRenderingMeshing[index]->isChecked(); + return _ui->checkBox_meshing->isChecked(); } double PreferencesDialog::getCloudVoxelSize(int index) const { - UASSERT(index >= 0 && index <= 2); + UASSERT(index >= 0 && index <= 1); return _3dRenderingVoxelSize[index]->value(); } int PreferencesDialog::getCloudDecimation(int index) const { - UASSERT(index >= 0 && index <= 2); + UASSERT(index >= 0 && index <= 1); return _3dRenderingDecimation[index]->value(); } double PreferencesDialog::getCloudMaxDepth(int index) const { - UASSERT(index >= 0 && index <= 2); + UASSERT(index >= 0 && index <= 1); return _3dRenderingMaxDepth[index]->value(); } double PreferencesDialog::getCloudOpacity(int index) const @@ -2481,7 +2426,7 @@ int PreferencesDialog::getCloudPointSize(int index) const bool PreferencesDialog::isScansShown(int index) const { - UASSERT(index >= 0 && index <= 2); + UASSERT(index >= 0 && index <= 1); return _3dRenderingShowScans[index]->isChecked(); } double PreferencesDialog::getScanOpacity(int index) const @@ -2494,25 +2439,21 @@ int PreferencesDialog::getScanPointSize(int index) const UASSERT(index >= 0 && index <= 1); return _3dRenderingPtSizeScan[index]->value(); } -int PreferencesDialog::getMeshNormalKSearch(int index) const +int PreferencesDialog::getMeshNormalKSearch() const { - UASSERT(index >= 0 && index <= 1); - return _3dRenderingNormalKSearch[index]->value(); + return _ui->spinBox_normalKSearch->value(); } -double PreferencesDialog::getMeshGP3Radius(int index) const +double PreferencesDialog::getMeshGP3Radius() const { - UASSERT(index >= 0 && index <= 1); - return _3dRenderingGP3Radius[index]->value(); + return _ui->doubleSpinBox_gp3Radius->value(); } -bool PreferencesDialog::getMeshSmoothing(int index) const +bool PreferencesDialog::getMeshSmoothing() const { - UASSERT(index == 0); - return _3dRenderingSmoothing[index]->isChecked(); + return _ui->checkBox_mls->isChecked(); } -double PreferencesDialog::getMeshSmoothingRadius(int index) const +double PreferencesDialog::getMeshSmoothingRadius() const { - UASSERT(index >= 0 && index <= 1); - return _3dRenderingSmoothingRadius[index]->value(); + return _ui->doubleSpinBox_mlsRadius->value(); } bool PreferencesDialog::isCloudFiltering() const { diff --git a/guilib/src/ui/exportCloudsDialog.ui b/guilib/src/ui/exportCloudsDialog.ui new file mode 100644 index 00000000..71cd12a9 --- /dev/null +++ b/guilib/src/ui/exportCloudsDialog.ui @@ -0,0 +1,342 @@ + + + ExportCloudsDialog + + + + 0 + 0 + 678 + 550 + + + + Export 3D clouds + + + + + + Regenerate clouds + + + true + + + + + + + + m + + + 3 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.005000000000000 + + + + + + + 3D cloud voxel size. + + + true + + + + + + + 1 + + + 32 + + + 1 + + + + + + + 3D cloud decimation (1-2-4-8-...). + + + true + + + + + + + m + + + 1 + + + 100.000000000000000 + + + 0.100000000000000 + + + 4.000000000000000 + + + + + + + 3D cloud maximum depth (0 means no limit). + + + true + + + + + + + + + + + + Assemble clouds to a single output cloud + + + true + + + + + + m + + + 3 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.005000000000000 + + + + + + + Voxel size. + + + true + + + + + + + + + + Mesh smoothing using Moving Least Squares algorithm (MLS) + + + true + + + false + + + + + + WARNING: This adds significative time to process, though the clouds will be more smooth. + + + true + + + + + + + + + m + + + 3 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.040000000000000 + + + + + + + MLS search radius: Set the sphere radius that is to be used for determining the k-nearest neighbors used for fitting. +Guidelines: 4 times the voxel size, 0.025 for voxel=0. + + + true + + + + + + + + + + + + Meshing using Greedy Projection Triangulation algorithm (GP3) + + + true + + + false + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + 0 + + + 20 + + + + + + + Set the number of k nearest neighbors to use for the normal estimation to create the mesh. Not used when mesh smoothing (MLS) above is used. + + + true + + + + + + + m + + + 3 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.040000000000000 + + + + + + + Sphere radius that is to be used for determining the k-nearest neighbors used for triangulating (GP3). +Guidelines: 4 times the voxel size, 0.025 for voxel=0. + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ExportCloudsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ExportCloudsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/guilib/src/ui/mainWindow.ui b/guilib/src/ui/mainWindow.ui index 9e89e7ce..53875b82 100644 --- a/guilib/src/ui/mainWindow.ui +++ b/guilib/src/ui/mainWindow.ui @@ -35,7 +35,7 @@ File - + @@ -63,7 +63,6 @@ - @@ -918,7 +917,7 @@ - Export point clouds (*.pcd *.ply *.vtk)... + Export 3D clouds (*.pcd *.ply)... @@ -964,17 +963,7 @@ - View high-res point clouds - - - - - View meshes - - - - - Export meshes (*.ply *.vtk)... + View high-res point clouds... @@ -1050,6 +1039,11 @@ Data recorder... + + + Export 2D grid map (*.bmp *.png)... + + diff --git a/guilib/src/ui/preferencesDialog.ui b/guilib/src/ui/preferencesDialog.ui index 2804e628..9fbcb329 100644 --- a/guilib/src/ui/preferencesDialog.ui +++ b/guilib/src/ui/preferencesDialog.ui @@ -63,9 +63,9 @@ 0 - -617 - 732 - 1198 + -185 + 737 + 893 @@ -86,7 +86,7 @@ QFrame::Raised - 3 + 1 @@ -418,8 +418,18 @@ Show a yellow background when the number of odometry inliers goes under this thr QFrame::Raised - - + + + + + 1 + + + 64 + + + + 3D cloud decimation (1-2-4-8-...). @@ -455,20 +465,6 @@ Show a yellow background when the number of odometry inliers goes under this thr - - - - Exporting/ -High-res view - - - Qt::AlignCenter - - - true - - - @@ -490,16 +486,6 @@ High-res view - - - - - - true - - - - Show 3D clouds. @@ -548,25 +534,6 @@ High-res view - - - m - - - 3 - - - 1.000000000000000 - - - 0.010000000000000 - - - 0.005000000000000 - - - - 3D cloud voxel size. @@ -602,19 +569,6 @@ High-res view - - - - 1 - - - 32 - - - 1 - - - @@ -654,25 +608,6 @@ High-res view - - - m - - - 1 - - - 100.000000000000000 - - - 0.100000000000000 - - - 4.000000000000000 - - - - 3D cloud maximum depth (0 means no limit). @@ -720,7 +655,7 @@ High-res view - + 3D cloud opacity. @@ -750,7 +685,7 @@ High-res view - + 3D cloud point size (1..64). @@ -781,16 +716,6 @@ High-res view - - - - - - true - - - - Show 2D scans. @@ -845,7 +770,7 @@ High-res view - + 2D scan opacity. @@ -855,16 +780,6 @@ High-res view - - - - 1 - - - 64 - - - @@ -875,7 +790,7 @@ High-res view - + 2D scan point size (1..64). @@ -885,7 +800,7 @@ High-res view - + Sphere radius that is to be used for determining the k-nearest neighbors used for triangulating (GP3). Guidelines: 4 times the voxel size, 0.025 for voxel=0. @@ -895,7 +810,7 @@ High-res view - + Mesh smoothing using Moving Least Squares algorithm (MLS). @@ -924,25 +839,6 @@ High-res view - - - - m - - - 3 - - - 1.000000000000000 - - - 0.010000000000000 - - - 0.040000000000000 - - - @@ -962,7 +858,7 @@ High-res view - + Online meshing using Greedy Projection Triangulation (GP3). @@ -972,7 +868,7 @@ High-res view - + MLS search radius: Set the sphere radius that is to be used for determining the k-nearest neighbors used for fitting. Guidelines: 4 times the voxel size, 0.025 for voxel=0. @@ -992,7 +888,7 @@ High-res view - + Set the number of k nearest neighbors to use for the normal estimation to create the mesh. Not used when mesh smoothing below is used. @@ -1009,35 +905,6 @@ High-res view - - - - 0 - - - 20 - - - - - - - m - - - 3 - - - 1.000000000000000 - - - 0.010000000000000 - - - 0.040000000000000 - - -