mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
Export Clouds: export scans integrated in the same dialog (remove export scans dialog)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<int, Signature>(),
|
||||
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
|
||||
std::map<int, cv::Mat>(),
|
||||
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<int, Transform> 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<int, Transform>::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<float> 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<pcl::PointNormal>::Ptr cloud;
|
||||
cloud = util3d::laserScanToPointCloudNormal(scan, data.laserScanInfo().localTransform());
|
||||
viewer->addCloud(uFormat("cloud%d", iter->first), cloud, pose, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::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<int, Signature>(),
|
||||
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> >(),
|
||||
std::map<int, cv::Mat>(),
|
||||
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<int, Transform> 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<pcl::PointXYZ>::Ptr assembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
for(std::map<int, Transform>::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<pcl::PointXYZ>::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())
|
||||
|
||||
@@ -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<int, Transform> & poses,
|
||||
const std::multimap<int, Link> & links,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const std::map<int, cv::Mat> & 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<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const std::map<int, cv::Mat> & 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<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const std::map<int, cv::Mat> & cachedScans,
|
||||
const QString & workingDirectory,
|
||||
const ParametersMap & parameters,
|
||||
std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::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<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::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<int, Transform> normalViewpoints = poses;
|
||||
if(_ui->checkBox_assemble->isChecked())
|
||||
{
|
||||
// Adjust view points with local transforms
|
||||
for(std::map<int, Transform>::iterator iter= normalViewpoints.begin(); iter!=normalViewpoints.end(); ++iter)
|
||||
{
|
||||
if(_ui->checkBox_fromDepth->isChecked())
|
||||
{
|
||||
std::vector<CameraModel> 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<pcl::PointXYZ>::Ptr rawAssembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
std::vector<int> 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<pcl::PointXYZ>::Ptr cloudWithoutNormals(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
pcl::copyPointCloud(*assembledCloud, *cloudWithoutNormals);
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloudWithoutNormals, indices, _ui->spinBox_normalKSearch->value());
|
||||
|
||||
UASSERT(assembledCloud->size() == normals->size());
|
||||
for(unsigned int i=0; i<normals->size(); ++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<int, Transform> 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<int, Transform>::iterator iter= mlsViewPoints.begin(); iter!=mlsViewPoints.end(); ++iter)
|
||||
{
|
||||
std::vector<CameraModel> 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<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> >::iterator iter=clouds.begin();
|
||||
iter!= clouds.end();
|
||||
++iter)
|
||||
iter!= clouds.end();)
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::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<pcl::PointXYZRGB>::Ptr cloudWithoutNormals(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||
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<pcl::PointXYZRGBNormal>::Ptr denseCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
|
||||
std::vector<pcl::Vertices> 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<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
||||
const std::map<int, Transform> & poses,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const ParametersMap & parameters) const
|
||||
const std::map<int, cv::Mat> & cachedScans,
|
||||
const ParametersMap & parameters,
|
||||
bool & has2dScans) const
|
||||
{
|
||||
has2dScans = false;
|
||||
std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::IndicesPtr> > clouds;
|
||||
int index=1;
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr previousCloud;
|
||||
@@ -2209,20 +2314,26 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::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<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!_ui->checkBox_fromDepth->isChecked() && !scan.empty())
|
||||
{
|
||||
bool is2D = scan.channels() == 2;
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::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; i<indices->size(); ++i)
|
||||
{
|
||||
indices->at(i) = i;
|
||||
}
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals;
|
||||
if(is2D)
|
||||
{
|
||||
// set nan normals
|
||||
normals.reset(new pcl::PointCloud<pcl::Normal>);
|
||||
normals->resize(cloudWithoutNormals->size());
|
||||
for(unsigned int i=0;i<cloudWithoutNormals->size(); ++i)
|
||||
{
|
||||
normals->points[i].normal_x =std::numeric_limits<float>::quiet_NaN();
|
||||
normals->points[i].normal_y =std::numeric_limits<float>::quiet_NaN();
|
||||
normals->points[i].normal_z =std::numeric_limits<float>::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<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(uContains(cachedClouds, iter->first))
|
||||
else if(_ui->checkBox_fromDepth->isChecked() && uContains(cachedClouds, iter->first))
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudWithoutNormals;
|
||||
if(!_ui->checkBox_meshing->isChecked() &&
|
||||
@@ -2406,9 +2570,88 @@ std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr, pcl::Indic
|
||||
pcl::PointCloud<pcl::Normal>::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<pcl::PointXYZRGB>::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; i<indices->size(); ++i)
|
||||
{
|
||||
indices->at(i) = i;
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::Ptr normals;
|
||||
if(is2D)
|
||||
{
|
||||
// set nan normals
|
||||
normals.reset(new pcl::PointCloud<pcl::Normal>);
|
||||
normals->resize(cloudWithoutNormals->size());
|
||||
for(unsigned int i=0;i<cloudWithoutNormals->size(); ++i)
|
||||
{
|
||||
normals->points[i].normal_x =std::numeric_limits<float>::quiet_NaN();
|
||||
normals->points[i].normal_y =std::numeric_limits<float>::quiet_NaN();
|
||||
normals->points[i].normal_z =std::numeric_limits<float>::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())
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const std::map<int, cv::Mat> & cachedScans,
|
||||
const QString & workingDirectory,
|
||||
const ParametersMap & parameters);
|
||||
|
||||
@@ -78,6 +79,7 @@ public:
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const std::map<int, cv::Mat> & cachedScans,
|
||||
const QString & workingDirectory,
|
||||
const ParametersMap & parameters);
|
||||
|
||||
@@ -100,13 +102,16 @@ private:
|
||||
const std::map<int, Transform> & poses,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const ParametersMap & parameters) const;
|
||||
const std::map<int, cv::Mat> & cachedScans,
|
||||
const ParametersMap & parameters,
|
||||
bool & has2dScans) const;
|
||||
bool getExportedClouds(
|
||||
const std::map<int, Transform> & poses,
|
||||
const std::multimap<int, Link> & links,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, std::pair<pcl::PointCloud<pcl::PointXYZRGB>::Ptr, pcl::IndicesPtr> > & cachedClouds,
|
||||
const std::map<int, cv::Mat> & cachedScans,
|
||||
const QString & workingDirectory,
|
||||
const ParametersMap & parameters,
|
||||
std::map<int, pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr> & clouds,
|
||||
@@ -120,7 +125,6 @@ private:
|
||||
|
||||
void setSaveButton();
|
||||
void setOkButton();
|
||||
void enableRegeneration(bool enabled);
|
||||
|
||||
void denseMeshPostProcessing(
|
||||
int id,
|
||||
|
||||
@@ -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 <pcl/conversions.h>
|
||||
#include <pcl/io/pcd_io.h>
|
||||
#include <pcl/io/ply_io.h>
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
|
||||
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<int, Transform> & poses,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdScans,
|
||||
const QString & workingDirectory)
|
||||
{
|
||||
std::map<int, pcl::PointCloud<pcl::PointNormal>::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<int, Transform> & poses,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdScans,
|
||||
const QString & workingDirectory)
|
||||
{
|
||||
std::map<int, pcl::PointCloud<pcl::PointNormal>::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<int, pcl::PointCloud<pcl::PointNormal>::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<int, Transform> & poses,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdClouds,
|
||||
const QString & workingDirectory,
|
||||
std::map<int, pcl::PointCloud<pcl::PointNormal>::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<int, pcl::PointCloud<pcl::PointNormal>::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<pcl::PointXYZ>::Ptr rawAssembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
std::vector<int> rawCameraIndices;
|
||||
int i =0;
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr assembledCloud(new pcl::PointCloud<pcl::PointNormal>);
|
||||
for(std::map<int, pcl::PointCloud<pcl::PointNormal>::Ptr>::iterator iter=clouds.begin();
|
||||
iter!= clouds.end();
|
||||
++iter)
|
||||
{
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr transformed(new pcl::PointCloud<pcl::PointNormal>);
|
||||
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<pcl::PointXYZ>::Ptr cloudXYZ(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
pcl::copyPointCloud(*assembledCloud, *cloudXYZ);
|
||||
|
||||
pcl::PointCloud<pcl::Normal>::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<int, pcl::PointCloud<pcl::PointNormal>::Ptr>::iterator iter=clouds.begin();
|
||||
iter!= clouds.end();
|
||||
++iter)
|
||||
{
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr cloudWithNormals = iter->second;
|
||||
|
||||
cloudsWithNormals.insert(std::make_pair(iter->first, cloudWithNormals));
|
||||
|
||||
_progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<int, pcl::PointCloud<pcl::PointNormal>::Ptr> ExportScansDialog::getScans(
|
||||
const std::map<int, Transform> & poses,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdScans) const
|
||||
{
|
||||
std::map<int, pcl::PointCloud<pcl::PointNormal>::Ptr> clouds;
|
||||
int i=0;
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr previousCloud;
|
||||
pcl::IndicesPtr previousIndices;
|
||||
Transform previousPose;
|
||||
for(std::map<int, Transform>::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<pcl::PointNormal>::Ptr cloud(new pcl::PointCloud<pcl::PointNormal>);
|
||||
if(scan.channels() == 6 && _ui->doubleSpinBox_voxelSize_assembled->value() == 0.0)
|
||||
{
|
||||
cloud = util3d::laserScanToPointCloudNormal(scan);
|
||||
}
|
||||
else
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::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<pcl::Normal>::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<pcl::PointNormal>::Ptr tmp(new pcl::PointCloud<pcl::PointNormal>);
|
||||
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<int, Transform> & poses,
|
||||
const std::map<int, pcl::PointCloud<pcl::PointNormal>::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<int, pcl::PointCloud<pcl::PointNormal>::Ptr >::const_iterator iter=clouds.begin(); iter!=clouds.end(); ++iter)
|
||||
{
|
||||
if(iter->second->size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointNormal>::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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <QDialog>
|
||||
#include <QMap>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <rtabmap/core/Signature.h>
|
||||
|
||||
#include <pcl/point_cloud.h>
|
||||
#include <pcl/point_types.h>
|
||||
#include <pcl/PolygonMesh.h>
|
||||
#include <pcl/TextureMesh.h>
|
||||
#include <pcl/pcl_base.h>
|
||||
|
||||
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<int, Transform> & poses,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdScans,
|
||||
const QString & workingDirectory);
|
||||
|
||||
void viewScans(
|
||||
const std::map<int, Transform> & poses,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdScans,
|
||||
const QString & workingDirectory);
|
||||
|
||||
signals:
|
||||
void configChanged();
|
||||
|
||||
public slots:
|
||||
void restoreDefaults();
|
||||
|
||||
private:
|
||||
std::map<int, pcl::PointCloud<pcl::PointNormal>::Ptr> getScans(
|
||||
const std::map<int, Transform> & poses,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdScans) const;
|
||||
bool getExportedScans(
|
||||
const std::map<int, Transform> & poses,
|
||||
const std::map<int, int> & mapIds,
|
||||
const QMap<int, Signature> & cachedSignatures,
|
||||
const std::map<int, cv::Mat> & createdScans,
|
||||
const QString & workingDirectory,
|
||||
std::map<int, pcl::PointCloud<pcl::PointNormal>::Ptr> & clouds);
|
||||
void saveScans(const QString & workingDirectory,
|
||||
const std::map<int, Transform> & poses,
|
||||
const std::map<int, pcl::PointCloud<pcl::PointNormal>::Ptr> & clouds,
|
||||
bool binaryMode = true);
|
||||
|
||||
void setSaveButton();
|
||||
void setOkButton();
|
||||
void enableRegeneration(bool enabled);
|
||||
|
||||
private:
|
||||
Ui_ExportScansDialog * _ui;
|
||||
ProgressDialog * _progressDialog;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* EXPORTSCANSDIALOG_H_ */
|
||||
@@ -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
|
||||
|
||||
@@ -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<const CloudViewer*>(widget);
|
||||
const ImageView * imageView = qobject_cast<const ImageView*>(widget);
|
||||
const ExportCloudsDialog * exportCloudsDialog = qobject_cast<const ExportCloudsDialog*>(widget);
|
||||
const ExportScansDialog * exportScansDialog = qobject_cast<const ExportScansDialog*>(widget);
|
||||
const PostProcessingDialog * postProcessingDialog = qobject_cast<const PostProcessingDialog *>(widget);
|
||||
const GraphViewer * graphViewer = qobject_cast<const GraphViewer *>(widget);
|
||||
const CalibrationDialog * calibrationDialog = qobject_cast<const CalibrationDialog *>(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<CloudViewer*>(widget);
|
||||
ImageView * imageView = qobject_cast<ImageView*>(widget);
|
||||
ExportCloudsDialog * exportCloudsDialog = qobject_cast<ExportCloudsDialog*>(widget);
|
||||
ExportScansDialog * exportScansDialog = qobject_cast<ExportScansDialog*>(widget);
|
||||
PostProcessingDialog * postProcessingDialog = qobject_cast<PostProcessingDialog *>(widget);
|
||||
GraphViewer * graphViewer = qobject_cast<GraphViewer *>(widget);
|
||||
CalibrationDialog * calibrationDialog = qobject_cast<CalibrationDialog *>(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);
|
||||
|
||||
@@ -506,7 +506,6 @@
|
||||
<addaction name="actionSave_config"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionGenerate_3D_map_pcd"/>
|
||||
<addaction name="actionExport_3D_laser_scans_ply_pcd"/>
|
||||
<addaction name="actionExport"/>
|
||||
<addaction name="actionExtract_images"/>
|
||||
<addaction name="menuExport_poses"/>
|
||||
@@ -533,7 +532,6 @@
|
||||
<addaction name="actionRestore_default_GUI_settings"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionView_3D_map"/>
|
||||
<addaction name="actionView_3D_laser_scans"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
@@ -2119,31 +2117,11 @@
|
||||
<string>Generate graph (*.dot) ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGenerate_graph_only_weighted_locations">
|
||||
<property name="text">
|
||||
<string>Generate graph (only weighted locations) ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClean_database">
|
||||
<property name="text">
|
||||
<string>Clean database</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGenerate_local_graph_dot">
|
||||
<property name="text">
|
||||
<string>Generate local graph (.dot) ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClean_local_graph">
|
||||
<property name="text">
|
||||
<string>Clean local graph ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUpdate_base_ids">
|
||||
<property name="text">
|
||||
<string>Update base ids</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGenerate_3D_map_pcd">
|
||||
<property name="text">
|
||||
<string>Export 3D map (*.ply *.pcd) ...</string>
|
||||
@@ -2195,16 +2173,6 @@
|
||||
<string>Reset link and grid map changes</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionView_3D_laser_scans">
|
||||
<property name="text">
|
||||
<string>View 2D-3D laser scans...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_3D_laser_scans_ply_pcd">
|
||||
<property name="text">
|
||||
<string>Export 2D-3D laser scans (*.ply *.pcd) ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRegenerate_local_grid_maps">
|
||||
<property name="text">
|
||||
<string>Regenerate local grid maps...</string>
|
||||
|
||||
@@ -25,23 +25,58 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>773</width>
|
||||
<height>3795</height>
|
||||
<height>3895</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_8" columnstretch="0,1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_12">
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="comboBox_pipeline">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Organized Point Cloud</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Dense Point Cloud</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Meshing.</string>
|
||||
<string>Reconstruction flavor.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_regenerate">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_filtering">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLabel" name="label_regenerate">
|
||||
<property name="text">
|
||||
<string>Regenerate clouds. This can be used to regenerate the point clouds at higher density than those used for online visualization.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="label_voxel">
|
||||
<property name="text">
|
||||
<string>Voxel size. Set 0 to disable. When organized meshes are assembled, this is the radius in which the vertices of the polygons are merged.</string>
|
||||
@@ -51,7 +86,44 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="11" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_gainCompensation">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_2">
|
||||
<property name="text">
|
||||
<string>Assemble clouds/meshes to a single output cloud/mesh.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QLabel" name="label_gainCompensation">
|
||||
<property name="text">
|
||||
<string>Gain compensation. Normalize brightness of images.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_frame">
|
||||
<property name="text">
|
||||
<string>Output frame.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_normalKSearch">
|
||||
<property name="minimum">
|
||||
<number>3</number>
|
||||
@@ -61,14 +133,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_meshing">
|
||||
<item row="12" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_12">
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string>Meshing.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_9">
|
||||
<property name="text">
|
||||
<string>Cloud filtering. Remove sparse points that are far from surfaces.</string>
|
||||
@@ -78,28 +153,31 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_smoothing">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_filtering">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile">
|
||||
<property name="text">
|
||||
<string>Binary file (for ply and pcd outputs).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_meshing">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_regenerate">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_10">
|
||||
<property name="text">
|
||||
<string>Cloud smoothing using Moving Least Squares algorithm (MLS).</string>
|
||||
@@ -109,7 +187,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize_assembled">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
@@ -128,55 +206,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Reconstruction flavor.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QComboBox" name="comboBox_pipeline">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Organized Point Cloud</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Dense Point Cloud</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile">
|
||||
<property name="text">
|
||||
<string>Binary file.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_8">
|
||||
<property name="text">
|
||||
<string>Regenerate clouds. This can be used to regenerate the point clouds at higher density than those used for online visualization.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_gainCompensation">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_normal">
|
||||
<property name="text">
|
||||
<string>Set the number of k nearest neighbors to use for the normal estimation.</string>
|
||||
@@ -186,7 +216,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_binary">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -196,44 +226,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_2">
|
||||
<property name="text">
|
||||
<string>Assemble clouds/meshes to a single output cloud/mesh.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_assemble">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="label_gainCompensation">
|
||||
<property name="text">
|
||||
<string>Gain compensation. Normalize brightness of images.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_frame">
|
||||
<property name="text">
|
||||
<string>Output frame.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QComboBox" name="comboBox_frame">
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -250,10 +250,67 @@
|
||||
<string>Camera</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Scan</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_11">
|
||||
<property name="text">
|
||||
<string>From RGB-D images. If not checked, clouds will be generated from laser scans.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_fromDepth">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_regenerateScans">
|
||||
<property name="title">
|
||||
<string>Regenerate clouds</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_18" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_decimation_scan">
|
||||
<property name="minimum">
|
||||
<number>-32</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_109">
|
||||
<property name="text">
|
||||
<string>Downsampling step.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_regenerate">
|
||||
<property name="title">
|
||||
|
||||
@@ -1,305 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ExportScansDialog</class>
|
||||
<widget class="QDialog" name="ExportScansDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>545</width>
|
||||
<height>439</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Export Scans</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,0,0">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>519</width>
|
||||
<height>363</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_8" columnstretch="0,1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile_2">
|
||||
<property name="text">
|
||||
<string>Assemble scans to a single output cloud.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_binary">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_assemble">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_109">
|
||||
<property name="text">
|
||||
<string>Voxel size. Set 0 to disable.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize_assembled">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.005000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_111">
|
||||
<property name="text">
|
||||
<string>Set the number of k nearest neighbors to use for the normal estimation. Set 0 to disable normal estimation.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_normalKSearch">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_binaryFile">
|
||||
<property name="text">
|
||||
<string>Binary file.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_regenerate">
|
||||
<property name="title">
|
||||
<string>Regenerate Scans</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_108">
|
||||
<property name="text">
|
||||
<string>Downsampling step.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_decimation">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_filtering">
|
||||
<property name="title">
|
||||
<string>Cloud Filtering (remove noisy points)</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_9" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_filteringRadius">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.020000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_110">
|
||||
<property name="text">
|
||||
<string>Radius search.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_filteringMinNeighbors">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_112">
|
||||
<property name="text">
|
||||
<string>Minimum neighbors in the search radius.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ExportScansDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ExportScansDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -27,7 +27,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1012</width>
|
||||
<height>25</height>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@@ -50,7 +50,6 @@
|
||||
<addaction name="actionSave_GUI_config"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSave_point_cloud"/>
|
||||
<addaction name="actionExport_2D_scans_ply_pcd"/>
|
||||
<addaction name="actionExport_2D_Grid_map_bmp_png"/>
|
||||
<addaction name="actionExport_octomap"/>
|
||||
<addaction name="menuExport_poses"/>
|
||||
@@ -83,7 +82,6 @@
|
||||
<addaction name="actionClear_cache"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionView_high_res_point_cloud"/>
|
||||
<addaction name="actionView_scans"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionDelete_memory"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -1074,7 +1072,7 @@
|
||||
</action>
|
||||
<action name="actionView_high_res_point_cloud">
|
||||
<property name="text">
|
||||
<string>View high-res point clouds...</string>
|
||||
<string>View point clouds...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTrigger_a_new_map">
|
||||
@@ -1150,16 +1148,6 @@
|
||||
<string>Export 2D grid map (*.png *.bmp)...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_2D_scans_ply_pcd">
|
||||
<property name="text">
|
||||
<string>Export 2D-3D scans (*.ply *.pcd)...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionView_scans">
|
||||
<property name="text">
|
||||
<string>View scans...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_database">
|
||||
<property name="icon">
|
||||
<iconset resource="../GuiLib.qrc">
|
||||
|
||||
Reference in New Issue
Block a user