diff --git a/guilib/include/rtabmap/gui/DatabaseViewer.h b/guilib/include/rtabmap/gui/DatabaseViewer.h index e0ffc432..a49ab2b0 100644 --- a/guilib/include/rtabmap/gui/DatabaseViewer.h +++ b/guilib/include/rtabmap/gui/DatabaseViewer.h @@ -98,9 +98,7 @@ private slots: void regenerateLocalMaps(); void regenerateCurrentLocalMaps(); void view3DMap(); - void view3DLaserScans(); void generate3DMap(); - void generate3DLaserScans(); void detectMoreLoopClosures(); void refineAllNeighborLinks(); void refineAllLoopClosureLinks(); diff --git a/guilib/include/rtabmap/gui/MainWindow.h b/guilib/include/rtabmap/gui/MainWindow.h index c5db7369..a6b8336e 100644 --- a/guilib/include/rtabmap/gui/MainWindow.h +++ b/guilib/include/rtabmap/gui/MainWindow.h @@ -67,7 +67,6 @@ class StatsToolBox; class ProgressDialog; class TwistGridWidget; class ExportCloudsDialog; -class ExportScansDialog; class PostProcessingDialog; class DepthCalibrationDialog; class DataRecorder; @@ -203,10 +202,8 @@ private slots: void setAspectRatio1080p(); void setAspectRatioCustom(); void exportGridMap(); - void exportScans(); void exportClouds(); void exportBundlerFormat(); - void viewScans(); void viewClouds(); void resetOdometry(); void triggerNewMap(); @@ -268,7 +265,6 @@ private: PreferencesDialog * _preferencesDialog; AboutDialog * _aboutDialog; ExportCloudsDialog * _exportCloudsDialog; - ExportScansDialog * _exportScansDialog; PostProcessingDialog * _postProcessingDialog; DepthCalibrationDialog * _depthCalibrationDialog; DataRecorder * _dataRecorder; diff --git a/guilib/src/CMakeLists.txt b/guilib/src/CMakeLists.txt index 131de7b5..d44329be 100644 --- a/guilib/src/CMakeLists.txt +++ b/guilib/src/CMakeLists.txt @@ -22,7 +22,6 @@ SET(headers_ui ./ExportDialog.h ./PostProcessingDialog.h ./ExportCloudsDialog.h - ./ExportScansDialog.h ./MapVisibilityWidget.h ../include/${PROJECT_PREFIX}/gui/GraphViewer.h ./CreateSimpleCalibrationDialog.h @@ -43,7 +42,6 @@ SET(uis ./ui/exportDialog.ui ./ui/postProcessingDialog.ui ./ui/exportCloudsDialog.ui - ./ui/exportScansDialog.ui ./ui/calibrationDialog.ui ./ui/createSimpleCalibrationDialog.ui ./ui/depthCalibrationDialog.ui @@ -91,7 +89,6 @@ SET(SRC_FILES ./ExportDialog.cpp ./PostProcessingDialog.cpp ./ExportCloudsDialog.cpp - ./ExportScansDialog.cpp ./MapVisibilityWidget.cpp ./GraphViewer.cpp ./EditDepthArea.cpp diff --git a/guilib/src/DatabaseViewer.cpp b/guilib/src/DatabaseViewer.cpp index b24c315a..8f49a807 100644 --- a/guilib/src/DatabaseViewer.cpp +++ b/guilib/src/DatabaseViewer.cpp @@ -230,9 +230,7 @@ DatabaseViewer::DatabaseViewer(const QString & ini, QWidget * parent) : connect(ui_->actionTORO_graph, SIGNAL(triggered()), this , SLOT(exportPosesTORO())); connect(ui_->actionG2o_g2o, SIGNAL(triggered()), this , SLOT(exportPosesG2O())); connect(ui_->actionView_3D_map, SIGNAL(triggered()), this, SLOT(view3DMap())); - connect(ui_->actionView_3D_laser_scans, SIGNAL(triggered()), this, SLOT(view3DLaserScans())); connect(ui_->actionGenerate_3D_map_pcd, SIGNAL(triggered()), this, SLOT(generate3DMap())); - connect(ui_->actionExport_3D_laser_scans_ply_pcd, SIGNAL(triggered()), this, SLOT(generate3DLaserScans())); connect(ui_->actionDetect_more_loop_closures, SIGNAL(triggered()), this, SLOT(detectMoreLoopClosures())); connect(ui_->actionRefine_all_neighbor_links, SIGNAL(triggered()), this, SLOT(refineAllNeighborLinks())); connect(ui_->actionRefine_all_loop_closure_links, SIGNAL(triggered()), this, SLOT(refineAllLoopClosureLinks())); @@ -2079,6 +2077,7 @@ void DatabaseViewer::view3DMap() mapIds_, QMap(), std::map::Ptr, pcl::IndicesPtr> >(), + std::map(), pathDatabase_, ui_->parameters_toolbox->getParameters()); } @@ -2088,118 +2087,6 @@ void DatabaseViewer::view3DMap() } } -void DatabaseViewer::view3DLaserScans() -{ - if(!ids_.size() || !dbDriver_) - { - QMessageBox::warning(this, tr("Cannot view 3D laser scans"), tr("The database is empty...")); - return; - } - - if(graphes_.empty()) - { - this->updateGraphView(); - if(graphes_.empty() || ui_->horizontalSlider_iterations->maximum() != (int)graphes_.size()-1) - { - QMessageBox::warning(this, tr("Cannot generate a graph"), tr("No graph in database?!")); - return; - } - } - bool ok = false; - int downsamplingStepSize = QInputDialog::getInt(this, tr("Downsampling?"), tr("Downsample step size (1 = no filtering)"), 1, 1, 99999, 1, &ok); - if(ok) - { - std::map optimizedPoses = uValueAt(graphes_, ui_->horizontalSlider_iterations->value()); - if(ui_->groupBox_posefiltering->isChecked()) - { - optimizedPoses = graph::radiusPosesFiltering(optimizedPoses, - ui_->doubleSpinBox_posefilteringRadius->value(), - ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0); - } - if(optimizedPoses.size() > 0) - { - rtabmap::ProgressDialog progressDialog(this); - progressDialog.setMaximumSteps((int)optimizedPoses.size()); - progressDialog.show(); - - // create a window - QDialog * window = new QDialog(this, Qt::Window); - window->setModal(this->isModal()); - window->setWindowTitle(tr("3D Laser Scans")); - window->setMinimumWidth(800); - window->setMinimumHeight(600); - - rtabmap::CloudViewer * viewer = new rtabmap::CloudViewer(window); - - QVBoxLayout *layout = new QVBoxLayout(); - layout->addWidget(viewer); - viewer->setCameraLockZ(false); - window->setLayout(layout); - connect(window, SIGNAL(finished(int)), viewer, SLOT(clear())); - - window->show(); - - for(std::map::const_iterator iter = optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter) - { - rtabmap::Transform pose = iter->second; - if(!pose.isNull()) - { - SensorData data; - dbDriver_->getNodeData(iter->first, data); - cv::Mat scan; - data.uncompressDataConst(0, 0, &scan); - - if(!scan.empty()) - { - if(downsamplingStepSize>1) - { - scan = util3d::downsample(scan, downsamplingStepSize); - } - - QColor color = Qt::red; - int mapId, weight; - Transform odomPose, groundTruth; - std::string label; - double stamp; - std::vector velocity; - if(dbDriver_->getNodeInfo(iter->first, odomPose, mapId, weight, label, stamp, groundTruth, velocity)) - { - color = (Qt::GlobalColor)(mapId % 12 + 7 ); - } - - if(scan.channels() == 6) - { - pcl::PointCloud::Ptr cloud; - cloud = util3d::laserScanToPointCloudNormal(scan, data.laserScanInfo().localTransform()); - viewer->addCloud(uFormat("cloud%d", iter->first), cloud, pose, color); - } - else - { - pcl::PointCloud::Ptr cloud; - cloud = util3d::laserScanToPointCloud(scan, data.laserScanInfo().localTransform()); - viewer->addCloud(uFormat("cloud%d", iter->first), cloud, pose, color); - } - UINFO("Generated %d (%d points)", iter->first, scan.cols); - progressDialog.appendText(QString("Generated %1 (%2 points)").arg(iter->first).arg(scan.cols)); - } - else - { - UINFO("Empty scan %d", iter->first); - progressDialog.appendText(QString("Empty scan %1").arg(iter->first)); - } - progressDialog.incrementStep(); - QApplication::processEvents(); - } - } - progressDialog.setValue(progressDialog.maximumSteps()); - } - else - { - QMessageBox::critical(this, tr("Error"), tr("No neighbors found for node %1.").arg(ui_->spinBox_optimizationsFrom->value())); - } - } -} - void DatabaseViewer::generate3DMap() { if(!ids_.size() || !dbDriver_) @@ -2233,6 +2120,7 @@ void DatabaseViewer::generate3DMap() mapIds_, QMap(), std::map::Ptr, pcl::IndicesPtr> >(), + std::map(), pathDatabase_, ui_->parameters_toolbox->getParameters()); } @@ -2242,103 +2130,6 @@ void DatabaseViewer::generate3DMap() } } -void DatabaseViewer::generate3DLaserScans() -{ - if(!ids_.size() || !dbDriver_) - { - QMessageBox::warning(this, tr("Cannot generate a graph"), tr("The database is empty...")); - return; - } - bool ok = false; - int downsamplingStepSize = QInputDialog::getInt(this, tr("Downsampling?"), tr("Downsample step size (1 = no filtering)"), 1, 1, 99999, 1, &ok); - if(ok) - { - QString path = QFileDialog::getSaveFileName(this, tr("Save point cloud"), - pathDatabase_+QDir::separator()+"cloud.ply", - tr("Point Cloud (*.ply *.pcd)")); - if(!path.isEmpty()) - { - std::map optimizedPoses = uValueAt(graphes_, ui_->horizontalSlider_iterations->value()); - if(ui_->groupBox_posefiltering->isChecked()) - { - optimizedPoses = graph::radiusPosesFiltering(optimizedPoses, - ui_->doubleSpinBox_posefilteringRadius->value(), - ui_->doubleSpinBox_posefilteringAngle->value()*CV_PI/180.0); - } - if(optimizedPoses.size() > 0) - { - rtabmap::ProgressDialog progressDialog; - progressDialog.setMaximumSteps((int)optimizedPoses.size()); - progressDialog.show(); - - pcl::PointCloud::Ptr assembledCloud(new pcl::PointCloud); - for(std::map::const_iterator iter = optimizedPoses.begin(); iter!=optimizedPoses.end(); ++iter) - { - const rtabmap::Transform & pose = iter->second; - if(!pose.isNull()) - { - SensorData data; - dbDriver_->getNodeData(iter->first, data); - cv::Mat scan; - data.uncompressDataConst(0, 0, &scan); - pcl::PointCloud::Ptr cloud; - UASSERT(scan.empty() || scan.type()==CV_32FC2 || scan.type() == CV_32FC3); - - if(downsamplingStepSize > 1) - { - scan = util3d::downsample(scan, downsamplingStepSize); - } - cloud = util3d::laserScanToPointCloud(scan, data.laserScanInfo().localTransform()); - - if(cloud->size()) - { - cloud = rtabmap::util3d::transformPointCloud(cloud, pose); - if(assembledCloud->size() == 0) - { - *assembledCloud = *cloud; - } - else - { - *assembledCloud += *cloud; - } - } - UINFO("Created cloud %d (%d points)", iter->first, (int)cloud->size()); - progressDialog.appendText(QString("Created cloud %1 (%2 points)").arg(iter->first).arg(cloud->size())); - - progressDialog.incrementStep(); - QApplication::processEvents(); - } - } - - if(assembledCloud->size()) - { - //voxelize by default to 1 cm - progressDialog.appendText(QString("Voxelize assembled cloud (%1 points)").arg(assembledCloud->size())); - QApplication::processEvents(); - assembledCloud = util3d::voxelize(assembledCloud, 0.01); - if(QFileInfo(path).suffix() == "ply") - { - pcl::io::savePLYFile(path.toStdString(), *assembledCloud); - } - else - { - pcl::io::savePCDFile(path.toStdString(), *assembledCloud); - } - progressDialog.appendText(QString("Saved %1 (%2 points)").arg(path).arg(assembledCloud->size())); - QApplication::processEvents(); - } - QMessageBox::information(this, tr("Finished"), tr("%1 clouds generated to %2.").arg(optimizedPoses.size()).arg(path)); - - progressDialog.setValue(progressDialog.maximumSteps()); - } - else - { - QMessageBox::critical(this, tr("Error"), tr("No neighbors found for node %1.").arg(ui_->spinBox_optimizationsFrom->value())); - } - } - } -} - void DatabaseViewer::detectMoreLoopClosures() { if(graphes_.empty()) diff --git a/guilib/src/ExportCloudsDialog.cpp b/guilib/src/ExportCloudsDialog.cpp index 822dbbb6..9524da73 100644 --- a/guilib/src/ExportCloudsDialog.cpp +++ b/guilib/src/ExportCloudsDialog.cpp @@ -84,6 +84,8 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) : restoreDefaults(); _ui->comboBox_upsamplingMethod->setItemData(1, 0, Qt::UserRole - 1); // disable DISTINCT_CLOUD + connect(_ui->checkBox_fromDepth, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged())); + connect(_ui->checkBox_fromDepth, SIGNAL(stateChanged(int)), this, SLOT(updateReconstructionFlavor())); connect(_ui->checkBox_binary, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged())); connect(_ui->spinBox_normalKSearch, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged())); connect(_ui->comboBox_pipeline, SIGNAL(currentIndexChanged(int)), this, SIGNAL(configChanged())); @@ -243,6 +245,7 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou settings.beginGroup(group); } settings.setValue("pipeline", _ui->comboBox_pipeline->currentIndex()); + settings.setValue("from_depth", _ui->checkBox_fromDepth->isChecked()); settings.setValue("binary", _ui->checkBox_binary->isChecked()); settings.setValue("normals_k", _ui->spinBox_normalKSearch->value()); @@ -351,6 +354,7 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou } _ui->comboBox_pipeline->setCurrentIndex(settings.value("pipeline", _ui->comboBox_pipeline->currentIndex()).toInt()); + _ui->checkBox_fromDepth->setChecked(settings.value("from_depth", _ui->checkBox_fromDepth->isChecked()).toBool()); _ui->checkBox_binary->setChecked(settings.value("binary", _ui->checkBox_binary->isChecked()).toBool()); _ui->spinBox_normalKSearch->setValue(settings.value("normals_k", _ui->spinBox_normalKSearch->value()).toInt()); @@ -459,6 +463,7 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou void ExportCloudsDialog::restoreDefaults() { _ui->comboBox_pipeline->setCurrentIndex(1); + _ui->checkBox_fromDepth->setChecked(true); _ui->checkBox_binary->setChecked(true); _ui->spinBox_normalKSearch->setValue(20); @@ -560,6 +565,28 @@ void ExportCloudsDialog::restoreDefaults() void ExportCloudsDialog::updateReconstructionFlavor() { + if(!_ui->checkBox_fromDepth->isChecked()) + { + _ui->comboBox_pipeline->setCurrentIndex(1); + _ui->comboBox_pipeline->setEnabled(false); + _ui->comboBox_frame->setItemData(2, 0,Qt::UserRole - 1); + _ui->comboBox_frame->setItemData(3, 1|32,Qt::UserRole - 1); + if(_ui->comboBox_frame->currentIndex() == 2) + { + _ui->comboBox_frame->setCurrentIndex(0); + } + } + else + { + _ui->comboBox_pipeline->setEnabled(true); + _ui->comboBox_frame->setItemData(2, 1|32,Qt::UserRole - 1); + _ui->comboBox_frame->setItemData(3, 0,Qt::UserRole - 1); + if(_ui->comboBox_frame->currentIndex() == 3) + { + _ui->comboBox_frame->setCurrentIndex(0); + } + } + _ui->checkBox_smoothing->setVisible(_ui->comboBox_pipeline->currentIndex() == 1); _ui->checkBox_smoothing->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1); @@ -570,7 +597,8 @@ void ExportCloudsDialog::updateReconstructionFlavor() _ui->checkBox_gainCompensation->setVisible(_ui->checkBox_gainCompensation->isEnabled()); _ui->label_gainCompensation->setVisible(_ui->checkBox_gainCompensation->isEnabled()); - _ui->groupBox_regenerate->setVisible(_ui->checkBox_regenerate->isChecked()); + _ui->groupBox_regenerate->setVisible(_ui->checkBox_regenerate->isChecked() && _ui->checkBox_fromDepth->isChecked()); + _ui->groupBox_regenerateScans->setVisible(_ui->checkBox_regenerate->isChecked() && !_ui->checkBox_fromDepth->isChecked()); _ui->groupBox_bilateral->setVisible(_ui->checkBox_bilateral->isChecked()); _ui->groupBox_filtering->setVisible(_ui->checkBox_filtering->isChecked()); _ui->groupBox_gain->setVisible(_ui->checkBox_gainCompensation->isEnabled() && _ui->checkBox_gainCompensation->isChecked()); @@ -668,21 +696,13 @@ void ExportCloudsDialog::setOkButton() updateReconstructionFlavor(); } -void ExportCloudsDialog::enableRegeneration(bool enabled) -{ - if(!enabled) - { - _ui->checkBox_regenerate->setChecked(false); - } - _ui->checkBox_regenerate->setEnabled(enabled); -} - void ExportCloudsDialog::exportClouds( const std::map & poses, const std::multimap & links, const std::map & mapIds, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, + const std::map & cachedScans, const QString & workingDirectory, const ParametersMap & parameters) { @@ -699,6 +719,7 @@ void ExportCloudsDialog::exportClouds( mapIds, cachedSignatures, cachedClouds, + cachedScans, workingDirectory, parameters, clouds, @@ -743,6 +764,7 @@ void ExportCloudsDialog::viewClouds( const std::map & mapIds, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, + const std::map & cachedScans, const QString & workingDirectory, const ParametersMap & parameters) { @@ -759,6 +781,7 @@ void ExportCloudsDialog::viewClouds( mapIds, cachedSignatures, cachedClouds, + cachedScans, workingDirectory, parameters, clouds, @@ -981,6 +1004,7 @@ bool ExportCloudsDialog::getExportedClouds( const std::map & mapIds, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, + const std::map & cachedScans, const QString & workingDirectory, const ParametersMap & parameters, std::map::Ptr> & cloudsWithNormals, @@ -990,10 +1014,11 @@ bool ExportCloudsDialog::getExportedClouds( { _canceled = false; _workingDirectory = workingDirectory; - enableRegeneration(_dbDriver || cachedSignatures.size()); + _ui->checkBox_regenerate->setEnabled(true); if(cachedSignatures.empty() && _dbDriver) { _ui->checkBox_regenerate->setChecked(true); + _ui->checkBox_regenerate->setEnabled(false); } if(_compensator) { @@ -1037,12 +1062,16 @@ bool ExportCloudsDialog::getExportedClouds( } _progressDialog->setMaximumSteps(int(poses.size())*mul+1); + bool has2dScans = false; std::map::Ptr, pcl::IndicesPtr> > clouds = this->getClouds( poses, cachedSignatures, cachedClouds, - parameters); + cachedScans, + parameters, + has2dScans); + UDEBUG(""); if(_canceled) { return false; @@ -1064,7 +1093,8 @@ bool ExportCloudsDialog::getExportedClouds( return false; } - if(_ui->checkBox_gainCompensation->isChecked() && clouds.size() > 1 && + UDEBUG(""); + if(_ui->checkBox_gainCompensation->isChecked() && _ui->checkBox_fromDepth->isChecked() && clouds.size() > 1 && // Do compensation later if we are merging textures on a dense assembled cloud !(_ui->checkBox_meshing->isChecked() && _ui->checkBox_textureMapping->isEnabled() && @@ -1137,6 +1167,59 @@ bool ExportCloudsDialog::getExportedClouds( } } + UDEBUG(""); + std::map normalViewpoints = poses; + if(_ui->checkBox_assemble->isChecked()) + { + // Adjust view points with local transforms + for(std::map::iterator iter= normalViewpoints.begin(); iter!=normalViewpoints.end(); ++iter) + { + if(_ui->checkBox_fromDepth->isChecked()) + { + std::vector models; + StereoCameraModel stereoModel; + if(cachedSignatures.contains(iter->first)) + { + const SensorData & data = cachedSignatures.find(iter->first)->sensorData(); + models = data.cameraModels(); + stereoModel = data.stereoCameraModel(); + } + else if(_dbDriver) + { + _dbDriver->getCalibration(iter->first, models, stereoModel); + } + + if(models.size() && !models[0].localTransform().isNull()) + { + iter->second *= models[0].localTransform(); + } + else if(!stereoModel.localTransform().isNull()) + { + iter->second *= stereoModel.localTransform(); + } + } + else + { + LaserScanInfo info; + if(cachedSignatures.contains(iter->first)) + { + const SensorData & data = cachedSignatures.find(iter->first)->sensorData(); + info = data.laserScanInfo(); + } + else if(_dbDriver) + { + _dbDriver->getLaserScanInfo(iter->first, info); + } + + if(!info.localTransform().isNull()) + { + iter->second *= info.localTransform(); + } + } + } + } + + UDEBUG(""); pcl::PointCloud::Ptr rawAssembledCloud(new pcl::PointCloud); std::vector rawCameraIndices; if(_ui->checkBox_assemble->isChecked() && @@ -1202,61 +1285,55 @@ bool ExportCloudsDialog::getExportedClouds( { indices->at(i) = i; } + + if(!_ui->checkBox_fromDepth->isChecked() && !has2dScans) + { + // recompute normals + pcl::PointCloud::Ptr cloudWithoutNormals(new pcl::PointCloud); + pcl::copyPointCloud(*assembledCloud, *cloudWithoutNormals); + pcl::PointCloud::Ptr normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value()); + + UASSERT(assembledCloud->size() == normals->size()); + for(unsigned int i=0; isize(); ++i) + { + assembledCloud->points[i].normal_x = normals->points[i].normal_x; + assembledCloud->points[i].normal_y = normals->points[i].normal_y; + assembledCloud->points[i].normal_z = normals->points[i].normal_z; + } + + // adjust with point of views + util3d::adjustNormalsToViewPoints( + normalViewpoints, + rawAssembledCloud, + rawCameraIndices, + assembledCloud); + } + clouds.insert(std::make_pair(0, std::make_pair(assembledCloud, indices))); } + UDEBUG(""); if(_canceled) { return false; } - std::map mlsViewPoints = poses; - if(_ui->checkBox_smoothing->isEnabled() && _ui->checkBox_smoothing->isChecked()) + if(_ui->checkBox_smoothing->isEnabled() && _ui->checkBox_smoothing->isChecked() && !has2dScans) { _progressDialog->appendText(tr("Smoothing the surface using Moving Least Squares (MLS) algorithm... " "[search radius=%1m voxel=%2m]").arg(_ui->doubleSpinBox_mlsRadius->value()).arg(_ui->doubleSpinBox_voxelSize_assembled->value())); QApplication::processEvents(); uSleep(100); QApplication::processEvents(); - - if(_ui->checkBox_assemble->isChecked()) - { - // Adjust view points with local transforms - for(std::map::iterator iter= mlsViewPoints.begin(); iter!=mlsViewPoints.end(); ++iter) - { - std::vector models; - StereoCameraModel stereoModel; - if(cachedSignatures.contains(iter->first)) - { - const SensorData & data = cachedSignatures.find(iter->first)->sensorData(); - models = data.cameraModels(); - stereoModel = data.stereoCameraModel(); - } - else if(_dbDriver) - { - _dbDriver->getCalibration(iter->first, models, stereoModel); - } - - if(models.size() && !models[0].localTransform().isNull()) - { - iter->second *= models[0].localTransform(); - } - else if(!stereoModel.localTransform().isNull()) - { - iter->second *= stereoModel.localTransform(); - } - } - } } //fill cloudWithNormals for(std::map::Ptr, pcl::IndicesPtr> >::iterator iter=clouds.begin(); - iter!= clouds.end(); - ++iter) + iter!= clouds.end();) { pcl::PointCloud::Ptr cloudWithNormals = iter->second.first; - if(_ui->checkBox_smoothing->isEnabled() && _ui->checkBox_smoothing->isChecked()) + if(_ui->checkBox_smoothing->isEnabled() && _ui->checkBox_smoothing->isChecked() && !has2dScans) { pcl::PointCloud::Ptr cloudWithoutNormals(new pcl::PointCloud); if(iter->second.second->size()) @@ -1306,7 +1383,7 @@ bool ExportCloudsDialog::getExportedClouds( _progressDialog->appendText(tr("Update %1 normals with %2 camera views...").arg(cloudWithNormals->size()).arg(poses.size())); util3d::adjustNormalsToViewPoints( - mlsViewPoints, + normalViewpoints, rawAssembledCloud, rawCameraIndices, cloudWithNormals); @@ -1319,6 +1396,9 @@ bool ExportCloudsDialog::getExportedClouds( cloudsWithNormals.insert(std::make_pair(iter->first, cloudWithNormals)); + // clear memory + clouds.erase(iter++); + _progressDialog->incrementStep(); QApplication::processEvents(); if(_canceled) @@ -1327,6 +1407,7 @@ bool ExportCloudsDialog::getExportedClouds( } } + UDEBUG(""); #ifdef RTABMAP_CPUTSDF cpu_tsdf::TSDFVolumeOctree::Ptr tsdf; #endif @@ -1337,7 +1418,7 @@ bool ExportCloudsDialog::getExportedClouds( //mesh UDEBUG("Meshing=%d", _ui->checkBox_meshing->isChecked()?1:0); - if(_ui->checkBox_meshing->isChecked()) + if(_ui->checkBox_meshing->isChecked() && !has2dScans) { if(_ui->comboBox_pipeline->currentIndex() == 0) { @@ -1521,7 +1602,7 @@ bool ExportCloudsDialog::getExportedClouds( if(polygons.size() == 0) { std::string msg = uFormat("All %d polygons filtered after polygon cluster filtering. Cluster minimum size is %d.", before, _ui->spinBox_mesh_minClusterSize->value()); - _progressDialog->appendText(msg.c_str()); + _progressDialog->appendText(msg.c_str(), Qt::darkYellow); UWARN(msg.c_str()); } @@ -1529,7 +1610,7 @@ bool ExportCloudsDialog::getExportedClouds( QApplication::processEvents(); } - _progressDialog->appendText(tr("Mesh %1 created with %2 polygons (%3/%4).").arg(iter->first).arg(polygons.size()).arg(++i).arg(clouds.size())); + _progressDialog->appendText(tr("Mesh %1 created with %2 polygons (%3/%4).").arg(iter->first).arg(polygons.size()).arg(++i).arg(cloudsWithNormals.size())); pcl::PointCloud::Ptr denseCloud(new pcl::PointCloud); std::vector densePolygons; @@ -1571,12 +1652,25 @@ bool ExportCloudsDialog::getExportedClouds( } else { - _progressDialog->appendText(tr("Mesh %1 not created (no valid points) (%2/%3).").arg(iter->first).arg(++i).arg(clouds.size())); + _progressDialog->appendText(tr("Mesh %1 not created (no valid points) (%2/%3).").arg(iter->first).arg(++i).arg(cloudsWithNormals.size())); } } else { - _progressDialog->appendText(tr("Mesh %1 not created (cloud is not organized). You may want to check cloud regeneration option (%2/%3).").arg(iter->first).arg(++i).arg(clouds.size())); + int weight = 0; + if(cachedSignatures.contains(iter->first)) + { + const Signature & s = cachedSignatures.find(iter->first).value(); + weight = s.getWeight(); + } + else if(_dbDriver) + { + _dbDriver->getWeight(iter->first, weight); + } + if(weight>=0) // don't show error for intermediate nodes + { + _progressDialog->appendText(tr("Mesh %1 not created (cloud is not organized). You may want to check cloud regeneration option (%2/%3).").arg(iter->first).arg(++i).arg(cloudsWithNormals.size())); + } } _progressDialog->incrementStep(); @@ -1694,7 +1788,14 @@ bool ExportCloudsDialog::getExportedClouds( } } } + else if(_ui->checkBox_meshing->isChecked()) + { + std::string msg = uFormat("Some clouds are 2D laser scans. Meshing can be done only from RGB-D clouds or 3D laser scans."); + _progressDialog->appendText(msg.c_str(), Qt::darkYellow); + UWARN(msg.c_str()); + } + UDEBUG(""); #ifdef RTABMAP_CPUTSDF if(tsdf.get()) { @@ -1780,6 +1881,7 @@ bool ExportCloudsDialog::getExportedClouds( } #endif + UDEBUG(""); if(_canceled) { return false; @@ -1787,7 +1889,7 @@ bool ExportCloudsDialog::getExportedClouds( // texture mesh UDEBUG("texture mapping=%d", _ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()?1:0); - if(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()) + if(!has2dScans && _ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()) { _progressDialog->appendText(tr("Texturing...")); QApplication::processEvents(); @@ -2083,7 +2185,7 @@ bool ExportCloudsDialog::getExportedClouds( if(validPolygons.size() == 0) { std::string msg = uFormat("All %d polygons filtered after polygon cluster filtering. Cluster minimum size is %d.",totalSize, _ui->spinBox_mesh_minClusterSize->value()); - _progressDialog->appendText(msg.c_str()); + _progressDialog->appendText(msg.c_str(), Qt::darkYellow); UWARN(msg.c_str()); } @@ -2190,8 +2292,11 @@ std::map::Ptr, pcl::Indic const std::map & poses, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, - const ParametersMap & parameters) const + const std::map & cachedScans, + const ParametersMap & parameters, + bool & has2dScans) const { + has2dScans = false; std::map::Ptr, pcl::IndicesPtr> > clouds; int index=1; pcl::PointCloud::Ptr previousCloud; @@ -2209,20 +2314,26 @@ std::map::Ptr, pcl::Indic if(_ui->checkBox_regenerate->isChecked()) { SensorData data; - cv::Mat image, depth; + cv::Mat image, depth, scan; if(cachedSignatures.contains(iter->first)) { const Signature & s = cachedSignatures.find(iter->first).value(); data = s.sensorData(); - data.uncompressData(&image, &depth, 0); + data.uncompressData( + _ui->checkBox_fromDepth->isChecked()?&image:0, + _ui->checkBox_fromDepth->isChecked()?&depth:0, + !_ui->checkBox_fromDepth->isChecked()?&scan:0); } else if(_dbDriver) { - _dbDriver->getNodeData(iter->first, data, true, false, false, false); - data.uncompressData(&image, &depth, 0); + _dbDriver->getNodeData(iter->first, data, _ui->checkBox_fromDepth->isChecked(), !_ui->checkBox_fromDepth->isChecked(), false, false); + data.uncompressData( + _ui->checkBox_fromDepth->isChecked()?&image:0, + _ui->checkBox_fromDepth->isChecked()?&depth:0, + !_ui->checkBox_fromDepth->isChecked()?&scan:0); } - if(!image.empty() && !depth.empty()) + if(_ui->checkBox_fromDepth->isChecked() && !image.empty() && !depth.empty()) { if(_ui->spinBox_fillDepthHoles->value() > 0) { @@ -2332,10 +2443,63 @@ std::map::Ptr, pcl::Indic } } } + else if(!_ui->checkBox_fromDepth->isChecked() && !scan.empty()) + { + bool is2D = scan.channels() == 2; + pcl::PointCloud::Ptr cloudWithoutNormals; + localTransform = Transform::getIdentity(); + Eigen::Vector3f viewPoint(0.0f,0.0f,0.0f); + if(_ui->comboBox_frame->isEnabled() && + _ui->comboBox_frame->currentIndex()!=3 && + !data.laserScanInfo().localTransform().isNull()) + { + localTransform = data.laserScanInfo().localTransform(); + viewPoint[0] = localTransform.x(); + viewPoint[1] = localTransform.y(); + viewPoint[2] = localTransform.z(); + } + cloudWithoutNormals = util3d::laserScanToPointCloudRGB(scan, localTransform); + if(cloudWithoutNormals->size()) + { + if(_ui->doubleSpinBox_voxelSize_assembled->value()>0.0) + { + cloudWithoutNormals = util3d::voxelize(cloudWithoutNormals, _ui->doubleSpinBox_voxelSize_assembled->value()); + } + indices->resize(cloudWithoutNormals->size()); + for(unsigned int i=0; isize(); ++i) + { + indices->at(i) = i; + } + pcl::PointCloud::Ptr normals; + if(is2D) + { + // set nan normals + normals.reset(new pcl::PointCloud); + normals->resize(cloudWithoutNormals->size()); + for(unsigned int i=0;isize(); ++i) + { + normals->points[i].normal_x =std::numeric_limits::quiet_NaN(); + normals->points[i].normal_y =std::numeric_limits::quiet_NaN(); + normals->points[i].normal_z =std::numeric_limits::quiet_NaN(); + } + has2dScans = true; + } + else + { + normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value(), viewPoint); + } + pcl::concatenateFields(*cloudWithoutNormals, *normals, *cloud); + } + } else { int weight = 0; - if(_dbDriver) + if(cachedSignatures.contains(iter->first)) + { + const Signature & s = cachedSignatures.find(iter->first).value(); + weight = s.getWeight(); + } + else if(_dbDriver) { _dbDriver->getWeight(iter->first, weight); } @@ -2345,7 +2509,7 @@ std::map::Ptr, pcl::Indic } } } - else if(uContains(cachedClouds, iter->first)) + else if(_ui->checkBox_fromDepth->isChecked() && uContains(cachedClouds, iter->first)) { pcl::PointCloud::Ptr cloudWithoutNormals; if(!_ui->checkBox_meshing->isChecked() && @@ -2406,9 +2570,88 @@ std::map::Ptr, pcl::Indic pcl::PointCloud::Ptr normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value(), viewPoint); pcl::concatenateFields(*cloudWithoutNormals, *normals, *cloud); } + else if(!_ui->checkBox_fromDepth->isChecked() && uContains(cachedScans, iter->first)) + { + pcl::PointCloud::Ptr cloudWithoutNormals; + localTransform = Transform::getIdentity(); + Eigen::Vector3f viewPoint(0.0f,0.0f,0.0f); + + LaserScanInfo info; + if(cachedSignatures.contains(iter->first)) + { + const Signature & s = cachedSignatures.find(iter->first).value(); + info = s.sensorData().laserScanInfo(); + } + else if(_dbDriver) + { + _dbDriver->getLaserScanInfo(iter->first, info); + } + + if(!info.localTransform().isNull()) + { + if(_ui->comboBox_frame->isEnabled() && _ui->comboBox_frame->currentIndex()!=3) + { + viewPoint[0] = localTransform.x(); + viewPoint[1] = localTransform.y(); + viewPoint[2] = localTransform.z(); + } + else + { + localTransform = info.localTransform().inverse(); + } + } + + bool is2D = cachedScans.at(iter->first).channels() == 2; + cloudWithoutNormals = util3d::laserScanToPointCloudRGB(cachedScans.at(iter->first), localTransform); + if(cloudWithoutNormals->size()) + { + if(_ui->doubleSpinBox_voxelSize_assembled->value()>0.0) + { + cloudWithoutNormals = util3d::voxelize(cloudWithoutNormals, _ui->doubleSpinBox_voxelSize_assembled->value()); + } + indices->resize(cloudWithoutNormals->size()); + for(unsigned int i=0; isize(); ++i) + { + indices->at(i) = i; + } + + pcl::PointCloud::Ptr normals; + if(is2D) + { + // set nan normals + normals.reset(new pcl::PointCloud); + normals->resize(cloudWithoutNormals->size()); + for(unsigned int i=0;isize(); ++i) + { + normals->points[i].normal_x =std::numeric_limits::quiet_NaN(); + normals->points[i].normal_y =std::numeric_limits::quiet_NaN(); + normals->points[i].normal_z =std::numeric_limits::quiet_NaN(); + } + has2dScans = true; + } + else + { + normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value(), viewPoint); + } + pcl::concatenateFields(*cloudWithoutNormals, *normals, *cloud); + } + } else { - _progressDialog->appendText(tr("Cached cloud %1 not found. You may want to regenerate the clouds (%2/%3).").arg(iter->first).arg(index).arg(poses.size()), Qt::darkYellow); + int weight = 0; + if(cachedSignatures.contains(iter->first)) + { + const Signature & s = cachedSignatures.find(iter->first).value(); + weight = s.getWeight(); + } + else if(_dbDriver) + { + _dbDriver->getWeight(iter->first, weight); + } + if(weight>=0) // don't show error for intermediate nodes + { + _progressDialog->appendText(tr("Cached cloud %1 not found. You may want to regenerate the clouds (%2/%3).").arg(iter->first).arg(index).arg(poses.size()), Qt::darkYellow); + } } if(indices->size()) diff --git a/guilib/src/ExportCloudsDialog.h b/guilib/src/ExportCloudsDialog.h index 3f390265..defee5b5 100644 --- a/guilib/src/ExportCloudsDialog.h +++ b/guilib/src/ExportCloudsDialog.h @@ -69,6 +69,7 @@ public: const std::map & mapIds, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, + const std::map & cachedScans, const QString & workingDirectory, const ParametersMap & parameters); @@ -78,6 +79,7 @@ public: const std::map & mapIds, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, + const std::map & cachedScans, const QString & workingDirectory, const ParametersMap & parameters); @@ -100,13 +102,16 @@ private: const std::map & poses, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, - const ParametersMap & parameters) const; + const std::map & cachedScans, + const ParametersMap & parameters, + bool & has2dScans) const; bool getExportedClouds( const std::map & poses, const std::multimap & links, const std::map & mapIds, const QMap & cachedSignatures, const std::map::Ptr, pcl::IndicesPtr> > & cachedClouds, + const std::map & cachedScans, const QString & workingDirectory, const ParametersMap & parameters, std::map::Ptr> & clouds, @@ -120,7 +125,6 @@ private: void setSaveButton(); void setOkButton(); - void enableRegeneration(bool enabled); void denseMeshPostProcessing( int id, diff --git a/guilib/src/ExportScansDialog.cpp b/guilib/src/ExportScansDialog.cpp deleted file mode 100644 index 66c347b2..00000000 --- a/guilib/src/ExportScansDialog.cpp +++ /dev/null @@ -1,597 +0,0 @@ -/* -Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Universite de Sherbrooke nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "ExportScansDialog.h" -#include "ui_exportScansDialog.h" - -#include "rtabmap/gui/ProgressDialog.h" -#include "rtabmap/gui/CloudViewer.h" -#include "rtabmap/utilite/ULogger.h" -#include "rtabmap/utilite/UConversion.h" -#include "rtabmap/utilite/UThread.h" -#include "rtabmap/utilite/UStl.h" - -#include "rtabmap/core/util3d_filtering.h" -#include "rtabmap/core/util3d_surface.h" -#include "rtabmap/core/util3d_transforms.h" -#include "rtabmap/core/util3d.h" -#include "rtabmap/core/Graph.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace rtabmap { - -ExportScansDialog::ExportScansDialog(QWidget *parent) : - QDialog(parent) -{ - _ui = new Ui_ExportScansDialog(); - _ui->setupUi(this); - - connect(_ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), this, SLOT(restoreDefaults())); - - restoreDefaults(); - - connect(_ui->checkBox_binary, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged())); - connect(_ui->spinBox_normalKSearch, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged())); - - connect(_ui->groupBox_regenerate, SIGNAL(clicked(bool)), this, SIGNAL(configChanged())); - connect(_ui->spinBox_decimation, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged())); - - connect(_ui->groupBox_filtering, SIGNAL(clicked(bool)), this, SIGNAL(configChanged())); - connect(_ui->doubleSpinBox_filteringRadius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged())); - connect(_ui->spinBox_filteringMinNeighbors, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged())); - - connect(_ui->checkBox_assemble, SIGNAL(clicked(bool)), this, SIGNAL(configChanged())); - connect(_ui->doubleSpinBox_voxelSize_assembled, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged())); - - _progressDialog = new ProgressDialog(this); - _progressDialog->setVisible(false); - _progressDialog->setAutoClose(true, 2); - _progressDialog->setMinimumWidth(600); -} - -ExportScansDialog::~ExportScansDialog() -{ - delete _ui; -} - -void ExportScansDialog::saveSettings(QSettings & settings, const QString & group) const -{ - if(!group.isEmpty()) - { - settings.beginGroup(group); - } - settings.setValue("binary", _ui->checkBox_binary->isChecked()); - settings.setValue("normals_k", _ui->spinBox_normalKSearch->value()); - - settings.setValue("regenerate", _ui->groupBox_regenerate->isChecked()); - settings.setValue("regenerate_decimation", _ui->spinBox_decimation->value()); - - settings.setValue("filtering", _ui->groupBox_filtering->isChecked()); - settings.setValue("filtering_radius", _ui->doubleSpinBox_filteringRadius->value()); - settings.setValue("filtering_min_neighbors", _ui->spinBox_filteringMinNeighbors->value()); - - settings.setValue("assemble", _ui->checkBox_assemble->isChecked()); - settings.setValue("assemble_voxel",_ui->doubleSpinBox_voxelSize_assembled->value()); - - if(!group.isEmpty()) - { - settings.endGroup(); - } -} - -void ExportScansDialog::loadSettings(QSettings & settings, const QString & group) -{ - if(!group.isEmpty()) - { - settings.beginGroup(group); - } - - _ui->checkBox_binary->setChecked(settings.value("binary", _ui->checkBox_binary->isChecked()).toBool()); - _ui->spinBox_normalKSearch->setValue(settings.value("normals_k", _ui->spinBox_normalKSearch->value()).toInt()); - - _ui->groupBox_regenerate->setChecked(settings.value("regenerate", _ui->groupBox_regenerate->isChecked()).toBool()); - _ui->spinBox_decimation->setValue(settings.value("regenerate_decimation", _ui->spinBox_decimation->value()).toInt()); - - _ui->groupBox_filtering->setChecked(settings.value("filtering", _ui->groupBox_filtering->isChecked()).toBool()); - _ui->doubleSpinBox_filteringRadius->setValue(settings.value("filtering_radius", _ui->doubleSpinBox_filteringRadius->value()).toDouble()); - _ui->spinBox_filteringMinNeighbors->setValue(settings.value("filtering_min_neighbors", _ui->spinBox_filteringMinNeighbors->value()).toInt()); - - _ui->checkBox_assemble->setChecked(settings.value("assemble", _ui->checkBox_assemble->isChecked()).toBool()); - _ui->doubleSpinBox_voxelSize_assembled->setValue(settings.value("assemble_voxel", _ui->doubleSpinBox_voxelSize_assembled->value()).toDouble()); - - if(!group.isEmpty()) - { - settings.endGroup(); - } -} - -void ExportScansDialog::restoreDefaults() -{ - _ui->checkBox_binary->setChecked(true); - _ui->spinBox_normalKSearch->setValue(20); - - _ui->groupBox_regenerate->setChecked(false); - _ui->spinBox_decimation->setValue(1); - - _ui->groupBox_filtering->setChecked(false); - _ui->doubleSpinBox_filteringRadius->setValue(0.02); - _ui->spinBox_filteringMinNeighbors->setValue(2); - - _ui->checkBox_assemble->setChecked(true); - _ui->doubleSpinBox_voxelSize_assembled->setValue(0.01); - - this->update(); -} - -void ExportScansDialog::setSaveButton() -{ - _ui->buttonBox->button(QDialogButtonBox::Ok)->setVisible(false); - _ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(true); - _ui->checkBox_binary->setVisible(true); - _ui->label_binaryFile->setVisible(true); -} - -void ExportScansDialog::setOkButton() -{ - _ui->buttonBox->button(QDialogButtonBox::Ok)->setVisible(true); - _ui->buttonBox->button(QDialogButtonBox::Save)->setVisible(false); - _ui->checkBox_binary->setVisible(false); - _ui->label_binaryFile->setVisible(false); -} - -void ExportScansDialog::enableRegeneration(bool enabled) -{ - if(!enabled) - { - _ui->groupBox_regenerate->setChecked(false); - } - _ui->groupBox_regenerate->setEnabled(enabled); -} - -void ExportScansDialog::exportScans( - const std::map & poses, - const std::map & mapIds, - const QMap & cachedSignatures, - const std::map & createdScans, - const QString & workingDirectory) -{ - std::map::Ptr> clouds; - - setSaveButton(); - - if(getExportedScans( - poses, - mapIds, - cachedSignatures, - createdScans, - workingDirectory, - clouds)) - { - saveScans(workingDirectory, poses, clouds, _ui->checkBox_binary->isChecked()); - _progressDialog->setValue(_progressDialog->maximumSteps()); - } -} - -void ExportScansDialog::viewScans( - const std::map & poses, - const std::map & mapIds, - const QMap & cachedSignatures, - const std::map & createdScans, - const QString & workingDirectory) -{ - std::map::Ptr> clouds; - - setOkButton(); - if(getExportedScans( - poses, - mapIds, - cachedSignatures, - createdScans, - workingDirectory, - clouds)) - { - QDialog * window = new QDialog(this->parentWidget()?this->parentWidget():this, Qt::Window); - window->setAttribute(Qt::WA_DeleteOnClose, true); - window->setWindowTitle(tr("Scans (%1 nodes)").arg(clouds.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); - connect(window, SIGNAL(finished(int)), viewer, SLOT(clear())); - - window->show(); - - uSleep(500); - if(clouds.size()) - { - for(std::map::Ptr>::iterator iter = clouds.begin(); iter!=clouds.end(); ++iter) - { - _progressDialog->appendText(tr("Viewing the cloud %1 (%2 points)...").arg(iter->first).arg(iter->second->size())); - _progressDialog->incrementStep(); - - QColor color = Qt::gray; - int mapId = uValue(mapIds, iter->first, -1); - if(mapId >= 0) - { - color = (Qt::GlobalColor)(mapId % 12 + 7 ); - } - viewer->addCloud(uFormat("cloud%d",iter->first), iter->second, iter->first>0?poses.at(iter->first):Transform::getIdentity()); - _progressDialog->appendText(tr("Viewing the cloud %1 (%2 points)... done.").arg(iter->first).arg(iter->second->size())); - } - } - - _progressDialog->setValue(_progressDialog->maximumSteps()); - viewer->update(); - } -} - -bool ExportScansDialog::getExportedScans( - const std::map & poses, - const std::map & mapIds, - const QMap & cachedSignatures, - const std::map & createdClouds, - const QString & workingDirectory, - std::map::Ptr> & cloudsWithNormals) -{ - enableRegeneration(cachedSignatures.size()); - if(this->exec() == QDialog::Accepted) - { - _progressDialog->resetProgress(); - _progressDialog->show(); - int mul = 1; - if(_ui->checkBox_assemble->isChecked()) - { - mul+=1; - } - mul+=1; // normals - _progressDialog->setMaximumSteps(int(poses.size())*mul+1); - - std::map::Ptr> clouds = this->getScans( - poses, - cachedSignatures, - createdClouds); - - if(_ui->checkBox_assemble->isChecked()) - { - _progressDialog->appendText(tr("Assembling %1 clouds...").arg(clouds.size())); - QApplication::processEvents(); - - pcl::PointCloud::Ptr rawAssembledCloud(new pcl::PointCloud); - std::vector rawCameraIndices; - int i =0; - pcl::PointCloud::Ptr assembledCloud(new pcl::PointCloud); - for(std::map::Ptr>::iterator iter=clouds.begin(); - iter!= clouds.end(); - ++iter) - { - pcl::PointCloud::Ptr transformed(new pcl::PointCloud); - transformed = util3d::transformPointCloud(iter->second, poses.at(iter->first)); - - *assembledCloud += *transformed; - - rawCameraIndices.resize(assembledCloud->size(), iter->first); - - _progressDialog->appendText(tr("Assembled cloud %1, total=%2 (%3/%4).").arg(iter->first).arg(assembledCloud->size()).arg(++i).arg(clouds.size())); - _progressDialog->incrementStep(); - QApplication::processEvents(); - } - - pcl::copyPointCloud(*assembledCloud, *rawAssembledCloud); - - if(_ui->doubleSpinBox_voxelSize_assembled->value()) - { - _progressDialog->appendText(tr("Voxelize cloud (%1 points, voxel size = %2 m)...") - .arg(assembledCloud->size()) - .arg(_ui->doubleSpinBox_voxelSize_assembled->value())); - QApplication::processEvents(); - - assembledCloud = util3d::voxelize( - assembledCloud, - _ui->doubleSpinBox_voxelSize_assembled->value()); - - if(_ui->spinBox_normalKSearch->value() > 0) - { - _progressDialog->appendText(tr("Compute normals (%1 points)...") - .arg(assembledCloud->size())); - QApplication::processEvents(); - - pcl::PointCloud::Ptr cloudXYZ(new pcl::PointCloud); - pcl::copyPointCloud(*assembledCloud, *cloudXYZ); - - pcl::PointCloud::Ptr normals = util3d::computeNormals(cloudXYZ, _ui->spinBox_normalKSearch->value()); - pcl::concatenateFields(*cloudXYZ, *normals, *assembledCloud); - - _progressDialog->appendText(tr("Update %1 normals with %2 camera views...") - .arg(assembledCloud->size()).arg(poses.size())); - util3d::adjustNormalsToViewPoints( - poses, - rawAssembledCloud, - rawCameraIndices, - assembledCloud); - } - } - - clouds.clear(); - clouds.insert(std::make_pair(0, assembledCloud)); - } - - //fill cloudWithNormals - for(std::map::Ptr>::iterator iter=clouds.begin(); - iter!= clouds.end(); - ++iter) - { - pcl::PointCloud::Ptr cloudWithNormals = iter->second; - - cloudsWithNormals.insert(std::make_pair(iter->first, cloudWithNormals)); - - _progressDialog->incrementStep(); - QApplication::processEvents(); - } - - return true; - } - return false; -} - -std::map::Ptr> ExportScansDialog::getScans( - const std::map & poses, - const QMap & cachedSignatures, - const std::map & createdScans) const -{ - std::map::Ptr> clouds; - int i=0; - pcl::PointCloud::Ptr previousCloud; - pcl::IndicesPtr previousIndices; - Transform previousPose; - for(std::map::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter) - { - int points = 0; - if(!iter->second.isNull()) - { - cv::Mat scan; - if(_ui->groupBox_regenerate->isChecked()) - { - if(cachedSignatures.contains(iter->first)) - { - const Signature & s = cachedSignatures.find(iter->first).value(); - SensorData d = s.sensorData(); - d.uncompressData(0, 0, &scan); - if(!scan.empty()) - { - if(_ui->spinBox_decimation->value() > 1) - { - scan = util3d::downsample(scan, _ui->spinBox_decimation->value()); - } - } - scan = util3d::transformLaserScan(scan, s.sensorData().laserScanInfo().localTransform()); - } - else - { - UERROR("Scan %d not found in cache!", iter->first); - } - } - else - { - scan = uValue(createdScans, iter->first, cv::Mat()); - } - - if(!scan.empty()) - { - pcl::PointCloud::Ptr cloud(new pcl::PointCloud); - if(scan.channels() == 6 && _ui->doubleSpinBox_voxelSize_assembled->value() == 0.0) - { - cloud = util3d::laserScanToPointCloudNormal(scan); - } - else - { - pcl::PointCloud::Ptr cloudXYZ = util3d::laserScanToPointCloud(scan); - - if(_ui->doubleSpinBox_voxelSize_assembled->value() > 0.0) - { - cloudXYZ = util3d::voxelize( - cloudXYZ, - _ui->doubleSpinBox_voxelSize_assembled->value()); - } - - if(!_ui->checkBox_assemble->isChecked() && _ui->spinBox_normalKSearch->value() > 0) - { - pcl::PointCloud::Ptr normals = util3d::computeNormals(cloudXYZ, _ui->spinBox_normalKSearch->value()); - pcl::concatenateFields(*cloudXYZ, *normals, *cloud); - } - else - { - pcl::copyPointCloud(*cloudXYZ, *cloud); - } - } - - if(cloud->size()) - { - if(_ui->groupBox_filtering->isChecked() && - _ui->doubleSpinBox_filteringRadius->value() > 0.0f && - _ui->spinBox_filteringMinNeighbors->value() > 0) - { - pcl::IndicesPtr indices = util3d::radiusFiltering(cloud, _ui->doubleSpinBox_filteringRadius->value(), _ui->spinBox_filteringMinNeighbors->value()); - pcl::PointCloud::Ptr tmp(new pcl::PointCloud); - pcl::copyPointCloud(*cloud, *indices, *tmp); - cloud = tmp; - } - - clouds.insert(std::make_pair(iter->first, cloud)); - points = cloud->size(); - } - } - } - else - { - UERROR("transform is null!?"); - } - - if(points>0) - { - _progressDialog->appendText(tr("Generated cloud %1 with %2 points (%3/%4).") - .arg(iter->first).arg(points).arg(++i).arg(poses.size())); - } - else - { - _progressDialog->appendText(tr("Ignored cloud %1 (%2/%3).").arg(iter->first).arg(++i).arg(poses.size())); - } - _progressDialog->incrementStep(); - QApplication::processEvents(); - } - - return clouds; -} - - -void ExportScansDialog::saveScans( - const QString & workingDirectory, - const std::map & poses, - const std::map::Ptr> & clouds, - bool binaryMode) -{ - if(clouds.size() == 1) - { - QString path = QFileDialog::getSaveFileName(this, tr("Save scan to ..."), workingDirectory+QDir::separator()+"scan.ply", tr("Point cloud data (*.ply *.pcd)")); - if(!path.isEmpty()) - { - if(clouds.begin()->second->size()) - { - _progressDialog->appendText(tr("Saving the scan (%1 points)...").arg(clouds.begin()->second->size())); - - bool success =false; - if(QFileInfo(path).suffix() == "pcd") - { - success = pcl::io::savePCDFile(path.toStdString(), *clouds.begin()->second, binaryMode) == 0; - } - else if(QFileInfo(path).suffix() == "ply") - { - success = pcl::io::savePLYFile(path.toStdString(), *clouds.begin()->second, binaryMode) == 0; - } - else if(QFileInfo(path).suffix() == "") - { - //use ply by default - path += ".ply"; - success = pcl::io::savePLYFile(path.toStdString(), *clouds.begin()->second, binaryMode) == 0; - } - else - { - UERROR("Extension not recognized! (%s) Should be one of (*.ply *.pcd).", QFileInfo(path).suffix().toStdString().c_str()); - } - if(success) - { - _progressDialog->incrementStep(); - _progressDialog->appendText(tr("Saving the scan (%1 points)... done.").arg(clouds.begin()->second->size())); - - QMessageBox::information(this, tr("Save successful!"), tr("Scan saved to \"%1\"").arg(path)); - } - else - { - QMessageBox::warning(this, tr("Save failed!"), tr("Failed to save to \"%1\"").arg(path)); - } - } - else - { - QMessageBox::warning(this, tr("Save failed!"), tr("Scan is empty...")); - } - } - } - else if(clouds.size()) - { - QString path = QFileDialog::getExistingDirectory(this, tr("Save scans to (*.ply *.pcd)..."), workingDirectory, 0); - if(!path.isEmpty()) - { - bool ok = false; - QStringList items; - items.push_back("ply"); - items.push_back("pcd"); - QString suffix = QInputDialog::getItem(this, tr("File format"), tr("Which format?"), items, 0, false, &ok); - - if(ok) - { - QString prefix = QInputDialog::getText(this, tr("File prefix"), tr("Prefix:"), QLineEdit::Normal, "scan", &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, poses.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, binaryMode) == 0; - } - else if(suffix == "ply") - { - success = pcl::io::savePLYFile(pathFile.toStdString(), *transformedCloud, binaryMode) == 0; - } - else - { - UFATAL("Extension not recognized! (%s)", suffix.toStdString().c_str()); - } - if(success) - { - _progressDialog->appendText(tr("Saved scan %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile)); - } - else - { - _progressDialog->appendText(tr("Failed saving scan %1 (%2 points) to %3.").arg(iter->first).arg(iter->second->size()).arg(pathFile)); - } - } - else - { - _progressDialog->appendText(tr("Scan %1 is empty!").arg(iter->first)); - } - _progressDialog->incrementStep(); - QApplication::processEvents(); - } - } - } - } - } -} - -} diff --git a/guilib/src/ExportScansDialog.h b/guilib/src/ExportScansDialog.h deleted file mode 100644 index 3737cbd3..00000000 --- a/guilib/src/ExportScansDialog.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Universite de Sherbrooke nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef EXPORTSCANSDIALOG_H_ -#define EXPORTSCANSDIALOG_H_ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -class Ui_ExportScansDialog; -class QAbstractButton; - -namespace rtabmap { -class ProgressDialog; - -class ExportScansDialog : public QDialog -{ - Q_OBJECT - -public: - ExportScansDialog(QWidget *parent = 0); - - virtual ~ExportScansDialog(); - - void saveSettings(QSettings & settings, const QString & group = "") const; - void loadSettings(QSettings & settings, const QString & group = ""); - - void exportScans( - const std::map & poses, - const std::map & mapIds, - const QMap & cachedSignatures, - const std::map & createdScans, - const QString & workingDirectory); - - void viewScans( - const std::map & poses, - const std::map & mapIds, - const QMap & cachedSignatures, - const std::map & createdScans, - const QString & workingDirectory); - -signals: - void configChanged(); - -public slots: - void restoreDefaults(); - -private: - std::map::Ptr> getScans( - const std::map & poses, - const QMap & cachedSignatures, - const std::map & createdScans) const; - bool getExportedScans( - const std::map & poses, - const std::map & mapIds, - const QMap & cachedSignatures, - const std::map & createdScans, - const QString & workingDirectory, - std::map::Ptr> & clouds); - void saveScans(const QString & workingDirectory, - const std::map & poses, - const std::map::Ptr> & clouds, - bool binaryMode = true); - - void setSaveButton(); - void setOkButton(); - void enableRegeneration(bool enabled); - -private: - Ui_ExportScansDialog * _ui; - ProgressDialog * _progressDialog; -}; - -} - -#endif /* EXPORTSCANSDIALOG_H_ */ diff --git a/guilib/src/MainWindow.cpp b/guilib/src/MainWindow.cpp index dd4e7080..70d7df8a 100644 --- a/guilib/src/MainWindow.cpp +++ b/guilib/src/MainWindow.cpp @@ -62,7 +62,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "rtabmap/utilite/UCv2Qt.h" #include "ExportCloudsDialog.h" -#include "ExportScansDialog.h" #include "AboutDialog.h" #include "PostProcessingDialog.h" #include "DepthCalibrationDialog.h" @@ -137,7 +136,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : _preferencesDialog(0), _aboutDialog(0), _exportCloudsDialog(0), - _exportScansDialog(0), _dataRecorder(0), _lastId(0), _firstStamp(0.0f), @@ -185,8 +183,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : _aboutDialog->setObjectName("AboutDialog"); _exportCloudsDialog = new ExportCloudsDialog(this); _exportCloudsDialog->setObjectName("ExportCloudsDialog"); - _exportScansDialog = new ExportScansDialog(this); - _exportScansDialog->setObjectName("ExportScansDialog"); _postProcessingDialog = new PostProcessingDialog(this); _postProcessingDialog->setObjectName("PostProcessingDialog"); _depthCalibrationDialog = new DepthCalibrationDialog(this); @@ -238,7 +234,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : _preferencesDialog->loadMainWindowState(this, _savedMaximized, statusBarShown); _preferencesDialog->loadWindowGeometry(_preferencesDialog); _preferencesDialog->loadWindowGeometry(_exportCloudsDialog); - _preferencesDialog->loadWindowGeometry(_exportScansDialog); _preferencesDialog->loadWindowGeometry(_postProcessingDialog); _preferencesDialog->loadWindowGeometry(_depthCalibrationDialog); _preferencesDialog->loadWindowGeometry(_aboutDialog); @@ -372,11 +367,9 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : connect(_ui->action1080p, SIGNAL(triggered()), this, SLOT(setAspectRatio1080p())); connect(_ui->actionCustom, SIGNAL(triggered()), this, SLOT(setAspectRatioCustom())); connect(_ui->actionSave_point_cloud, SIGNAL(triggered()), this, SLOT(exportClouds())); - connect(_ui->actionExport_2D_scans_ply_pcd, SIGNAL(triggered()), this, SLOT(exportScans())); connect(_ui->actionExport_2D_Grid_map_bmp_png, SIGNAL(triggered()), this, SLOT(exportGridMap())); connect(_ui->actionExport_images_RGB_jpg_Depth_png, SIGNAL(triggered()), this , SLOT(exportImages())); connect(_ui->actionExport_cameras_in_Bundle_format_out, SIGNAL(triggered()), SLOT(exportBundlerFormat())); - connect(_ui->actionView_scans, SIGNAL(triggered()), this, SLOT(viewScans())); connect(_ui->actionExport_octomap, SIGNAL(triggered()), this, SLOT(exportOctomap())); connect(_ui->actionView_high_res_point_cloud, SIGNAL(triggered()), this, SLOT(viewClouds())); connect(_ui->actionReset_Odometry, SIGNAL(triggered()), this, SLOT(resetOdometry())); @@ -467,7 +460,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : connect(_ui->graphicsView_graphView, SIGNAL(configChanged()), this, SLOT(configGUIModified())); connect(_cloudViewer, SIGNAL(configChanged()), this, SLOT(configGUIModified())); connect(_exportCloudsDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified())); - connect(_exportScansDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified())); connect(_postProcessingDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified())); connect(_depthCalibrationDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified())); connect(_ui->toolBar->toggleViewAction(), SIGNAL(toggled(bool)), this, SLOT(configGUIModified())); @@ -528,7 +520,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) : //dialog states _preferencesDialog->loadWidgetState(_exportCloudsDialog); - _preferencesDialog->loadWidgetState(_exportScansDialog); _preferencesDialog->loadWidgetState(_postProcessingDialog); _preferencesDialog->loadWidgetState(_depthCalibrationDialog); @@ -2494,9 +2485,7 @@ void MainWindow::updateMapCloud( { _ui->actionSave_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); _ui->actionView_high_res_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty()); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_occupancyGrid->addedNodes().empty()); - _ui->actionView_scans->setEnabled(!_createdScans.empty()); #ifdef RTABMAP_OCTOMAP _ui->actionExport_octomap->setEnabled(_octomap->octree()->size()); #else @@ -2990,7 +2979,14 @@ void MainWindow::createAndAddScanToMap(int nodeId, const Transform & pose, int m if(filtered) { //reconvert the voxelized cloud - scan = util3d::laserScanFromPointCloud(*cloud); + if(scan.channels() == 2) + { + scan = util3d::laserScan2dFromPointCloud(*cloud); + } + else + { + scan = util3d::laserScanFromPointCloud(*cloud); + } } else { @@ -4106,7 +4102,6 @@ void MainWindow::saveConfigGUI() _preferencesDialog->saveWidgetState(_ui->imageView_loopClosure); _preferencesDialog->saveWidgetState(_ui->imageView_odometry); _preferencesDialog->saveWidgetState(_exportCloudsDialog); - _preferencesDialog->saveWidgetState(_exportScansDialog); _preferencesDialog->saveWidgetState(_postProcessingDialog); _preferencesDialog->saveWidgetState(_depthCalibrationDialog); _preferencesDialog->saveWidgetState(_ui->graphicsView_graphView); @@ -5800,13 +5795,11 @@ void MainWindow::clearTheCache() _ui->statsToolBox->clear(); //disable save cloud action _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(false); _ui->actionPost_processing->setEnabled(false); _ui->actionSave_point_cloud->setEnabled(false); _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false); _ui->actionDepth_Calibration->setEnabled(false); _ui->actionExport_images_RGB_jpg_Depth_png->setEnabled(false); - _ui->actionView_scans->setEnabled(false); _ui->actionExport_octomap->setEnabled(false); _ui->actionView_high_res_point_cloud->setEnabled(false); _likelihoodCurve->clear(); @@ -6162,37 +6155,6 @@ void MainWindow::exportGridMap() } } -void MainWindow::exportScans() -{ - if(_exportScansDialog->isVisible()) - { - return; - } - - _exportScansDialog->exportScans( - _currentPosesMap, - _currentMapIds, - _cachedSignatures, - _createdScans, - _preferencesDialog->getWorkingDirectory()); -} - -void MainWindow::viewScans() -{ - if(_exportScansDialog->isVisible()) - { - return; - } - - _exportScansDialog->viewScans( - _ui->widget_mapVisibility->getVisiblePoses(), - _currentMapIds, - _cachedSignatures, - _createdScans, - _preferencesDialog->getWorkingDirectory()); - -} - void MainWindow::exportClouds() { if(_exportCloudsDialog->isVisible()) @@ -6225,6 +6187,7 @@ void MainWindow::exportClouds() _currentMapIds, _cachedSignatures, _cachedClouds, + _createdScans, _preferencesDialog->getWorkingDirectory(), _preferencesDialog->getAllParameters()); } @@ -6261,6 +6224,7 @@ void MainWindow::viewClouds() _currentMapIds, _cachedSignatures, _cachedClouds, + _createdScans, _preferencesDialog->getWorkingDirectory(), _preferencesDialog->getAllParameters()); @@ -6780,9 +6744,7 @@ void MainWindow::changeState(MainWindow::State newState) _ui->menuExport_poses->setEnabled(!_currentPosesMap.empty()); _ui->actionSave_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); _ui->actionView_high_res_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty()); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_occupancyGrid->addedNodes().empty()); - _ui->actionView_scans->setEnabled(!_createdScans.empty()); #ifdef RTABMAP_OCTOMAP _ui->actionExport_octomap->setEnabled(_octomap->octree()->size()); #else @@ -6842,9 +6804,7 @@ void MainWindow::changeState(MainWindow::State newState) _ui->menuExport_poses->setEnabled(!_currentPosesMap.empty()); _ui->actionSave_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); _ui->actionView_high_res_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty()); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_occupancyGrid->addedNodes().empty()); - _ui->actionView_scans->setEnabled(!_createdScans.empty()); #ifdef RTABMAP_OCTOMAP _ui->actionExport_octomap->setEnabled(_octomap->octree()->size()); #else @@ -6893,9 +6853,7 @@ void MainWindow::changeState(MainWindow::State newState) _ui->menuExport_poses->setEnabled(false); _ui->actionSave_point_cloud->setEnabled(false); _ui->actionView_high_res_point_cloud->setEnabled(false); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(false); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false); - _ui->actionView_scans->setEnabled(false); _ui->actionExport_octomap->setEnabled(false); _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false); _ui->actionDepth_Calibration->setEnabled(false); @@ -6937,9 +6895,7 @@ void MainWindow::changeState(MainWindow::State newState) _ui->menuExport_poses->setEnabled(false); _ui->actionSave_point_cloud->setEnabled(false); _ui->actionView_high_res_point_cloud->setEnabled(false); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(false); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false); - _ui->actionView_scans->setEnabled(false); _ui->actionExport_octomap->setEnabled(false); _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false); _ui->actionDepth_Calibration->setEnabled(false); @@ -6968,9 +6924,7 @@ void MainWindow::changeState(MainWindow::State newState) _ui->menuExport_poses->setEnabled(!_currentPosesMap.empty()); _ui->actionSave_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); _ui->actionView_high_res_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty()); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_occupancyGrid->addedNodes().empty()); - _ui->actionView_scans->setEnabled(!_createdScans.empty()); #ifdef RTABMAP_OCTOMAP _ui->actionExport_octomap->setEnabled(_octomap->octree()->size()); #else @@ -7003,9 +6957,7 @@ void MainWindow::changeState(MainWindow::State newState) _ui->menuExport_poses->setEnabled(false); _ui->actionSave_point_cloud->setEnabled(false); _ui->actionView_high_res_point_cloud->setEnabled(false); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(false); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(false); - _ui->actionView_scans->setEnabled(false); _ui->actionExport_octomap->setEnabled(false); _ui->actionExport_cameras_in_Bundle_format_out->setEnabled(false); _ui->actionDepth_Calibration->setEnabled(false); @@ -7035,9 +6987,7 @@ void MainWindow::changeState(MainWindow::State newState) _ui->menuExport_poses->setEnabled(!_currentPosesMap.empty()); _ui->actionSave_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); _ui->actionView_high_res_point_cloud->setEnabled(!_cachedSignatures.empty() || !_cachedClouds.empty()); - _ui->actionExport_2D_scans_ply_pcd->setEnabled(!_createdScans.empty()); _ui->actionExport_2D_Grid_map_bmp_png->setEnabled(!_occupancyGrid->addedNodes().empty()); - _ui->actionView_scans->setEnabled(!_createdScans.empty()); #ifdef RTABMAP_OCTOMAP _ui->actionExport_octomap->setEnabled(_octomap->octree()->size()); #else diff --git a/guilib/src/PreferencesDialog.cpp b/guilib/src/PreferencesDialog.cpp index faccf23a..0d56f52b 100644 --- a/guilib/src/PreferencesDialog.cpp +++ b/guilib/src/PreferencesDialog.cpp @@ -69,7 +69,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "rtabmap/gui/ImageView.h" #include "rtabmap/gui/GraphViewer.h" #include "ExportCloudsDialog.h" -#include "ExportScansDialog.h" #include "PostProcessingDialog.h" #include "CreateSimpleCalibrationDialog.h" #include "DepthCalibrationDialog.h" @@ -2697,7 +2696,6 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget) const CloudViewer * cloudViewer = qobject_cast(widget); const ImageView * imageView = qobject_cast(widget); const ExportCloudsDialog * exportCloudsDialog = qobject_cast(widget); - const ExportScansDialog * exportScansDialog = qobject_cast(widget); const PostProcessingDialog * postProcessingDialog = qobject_cast(widget); const GraphViewer * graphViewer = qobject_cast(widget); const CalibrationDialog * calibrationDialog = qobject_cast(widget); @@ -2718,11 +2716,6 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget) exportCloudsDialog->saveSettings(settings); exportCloudsDialog->saveSettings(settingsTmp); } - else if(exportScansDialog) - { - exportScansDialog->saveSettings(settings); - exportScansDialog->saveSettings(settingsTmp); - } else if(postProcessingDialog) { postProcessingDialog->saveSettings(settings); @@ -2771,7 +2764,6 @@ void PreferencesDialog::loadWidgetState(QWidget * widget) CloudViewer * cloudViewer = qobject_cast(widget); ImageView * imageView = qobject_cast(widget); ExportCloudsDialog * exportCloudsDialog = qobject_cast(widget); - ExportScansDialog * exportScansDialog = qobject_cast(widget); PostProcessingDialog * postProcessingDialog = qobject_cast(widget); GraphViewer * graphViewer = qobject_cast(widget); CalibrationDialog * calibrationDialog = qobject_cast(widget); @@ -2792,11 +2784,6 @@ void PreferencesDialog::loadWidgetState(QWidget * widget) exportCloudsDialog->loadSettings(settings); exportCloudsDialog->saveSettings(settingsTmp); } - else if(exportScansDialog) - { - exportScansDialog->loadSettings(settings); - exportScansDialog->saveSettings(settingsTmp); - } else if(postProcessingDialog) { postProcessingDialog->loadSettings(settings); diff --git a/guilib/src/ui/DatabaseViewer.ui b/guilib/src/ui/DatabaseViewer.ui index 7c110885..f2bbcf84 100644 --- a/guilib/src/ui/DatabaseViewer.ui +++ b/guilib/src/ui/DatabaseViewer.ui @@ -506,7 +506,6 @@ - @@ -533,7 +532,6 @@ - @@ -2119,31 +2117,11 @@ Generate graph (*.dot) ... - - - Generate graph (only weighted locations) ... - - - - - Clean database - - Generate local graph (.dot) ... - - - Clean local graph ... - - - - - Update base ids - - Export 3D map (*.ply *.pcd) ... @@ -2195,16 +2173,6 @@ Reset link and grid map changes - - - View 2D-3D laser scans... - - - - - Export 2D-3D laser scans (*.ply *.pcd) ... - - Regenerate local grid maps... diff --git a/guilib/src/ui/exportCloudsDialog.ui b/guilib/src/ui/exportCloudsDialog.ui index a540a8d4..d23aa185 100644 --- a/guilib/src/ui/exportCloudsDialog.ui +++ b/guilib/src/ui/exportCloudsDialog.ui @@ -25,23 +25,58 @@ 0 0 773 - 3795 + 3895 - - + + + + + Organized Point Cloud + + + + + Dense Point Cloud + + + + + + - Meshing. + Reconstruction flavor. + + + + + + + + + + + + + + + + + + + + + Regenerate clouds. This can be used to regenerate the point clouds at higher density than those used for online visualization. true - + Voxel size. Set 0 to disable. When organized meshes are assembled, this is the radius in which the vertices of the polygons are merged. @@ -51,7 +86,44 @@ - + + + + + + + + + + + Assemble clouds/meshes to a single output cloud/mesh. + + + true + + + + + + + Gain compensation. Normalize brightness of images. + + + true + + + + + + + Output frame. + + + true + + + + 3 @@ -61,14 +133,17 @@ - - + + - + Meshing. + + + true - + Cloud filtering. Remove sparse points that are far from surfaces. @@ -78,28 +153,31 @@ - + - - + + + + Binary file (for ply and pcd outputs). + + + true + + + + + - - - - - - - - + Cloud smoothing using Moving Least Squares algorithm (MLS). @@ -109,7 +187,7 @@ - + m @@ -128,55 +206,7 @@ - - - - Reconstruction flavor. - - - - - - - - Organized Point Cloud - - - - - Dense Point Cloud - - - - - - - - Binary file. - - - true - - - - - - Regenerate clouds. This can be used to regenerate the point clouds at higher density than those used for online visualization. - - - true - - - - - - - - - - - Set the number of k nearest neighbors to use for the normal estimation. @@ -186,7 +216,7 @@ - + @@ -196,44 +226,14 @@ - - - - Assemble clouds/meshes to a single output cloud/mesh. - - - true - - - - + - - - - Gain compensation. Normalize brightness of images. - - - true - - - - - - - Output frame. - - - true - - - - + @@ -250,10 +250,67 @@ Camera + + + Scan + + + + + + + + From RGB-D images. If not checked, clouds will be generated from laser scans. + + + true + + + + + + + + + + true + + + + + Regenerate clouds + + + + + + -32 + + + 32 + + + 1 + + + + + + + Downsampling step. + + + true + + + + + + diff --git a/guilib/src/ui/exportScansDialog.ui b/guilib/src/ui/exportScansDialog.ui deleted file mode 100644 index 7280571a..00000000 --- a/guilib/src/ui/exportScansDialog.ui +++ /dev/null @@ -1,305 +0,0 @@ - - - ExportScansDialog - - - - 0 - 0 - 545 - 439 - - - - Export Scans - - - - - - true - - - - - 0 - 0 - 519 - 363 - - - - - - - - - Assemble scans to a single output cloud. - - - true - - - - - - - - - - true - - - - - - - - - - - - - - Voxel size. Set 0 to disable. - - - true - - - - - - - m - - - 3 - - - 1.000000000000000 - - - 0.010000000000000 - - - 0.005000000000000 - - - - - - - Set the number of k nearest neighbors to use for the normal estimation. Set 0 to disable normal estimation. - - - true - - - - - - - 0 - - - 20 - - - - - - - Binary file. - - - true - - - - - - - - - Regenerate Scans - - - true - - - - - - - - Downsampling step. - - - true - - - - - - - 1 - - - 999 - - - 1 - - - - - - - - - - - - Cloud Filtering (remove noisy points) - - - true - - - - - - m - - - 3 - - - 0.001000000000000 - - - 1.000000000000000 - - - 0.010000000000000 - - - 0.020000000000000 - - - - - - - Radius search. - - - true - - - - - - - 1 - - - 100 - - - 2 - - - - - - - Minimum neighbors in the search radius. - - - true - - - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save - - - - - - - - - buttonBox - accepted() - ExportScansDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - ExportScansDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/guilib/src/ui/mainWindow.ui b/guilib/src/ui/mainWindow.ui index 544decae..a628b636 100644 --- a/guilib/src/ui/mainWindow.ui +++ b/guilib/src/ui/mainWindow.ui @@ -27,7 +27,7 @@ 0 0 1012 - 25 + 22 @@ -50,7 +50,6 @@ - @@ -83,7 +82,6 @@ - @@ -1074,7 +1072,7 @@ - View high-res point clouds... + View point clouds... @@ -1150,16 +1148,6 @@ Export 2D grid map (*.png *.bmp)... - - - Export 2D-3D scans (*.ply *.pcd)... - - - - - View scans... - -