Export: CPU-TSDF mesh reconstruction integration

This commit is contained in:
matlabbe
2017-05-05 21:44:06 -04:00
parent b25379c243
commit eadeb3841b
8 changed files with 1062 additions and 522 deletions
+21
View File
@@ -151,6 +151,7 @@ option(WITH_ZED "Include ZED sdk support" ON)
option(WITH_REALSENSE "Include RealSense support" ON)
option(WITH_REALSENSE_SLAM "Include RealSenseSlam support" ON)
option(WITH_OCTOMAP "Include Octomap support" ON)
option(WITH_CPUTSDF "Include CPUTSDF support" ON)
option(PCL_OMP "With PCL OMP implementations" ON)
FIND_PACKAGE(OpenCV REQUIRED QUIET)
@@ -336,6 +337,13 @@ IF(WITH_OCTOMAP)
ENDIF(OCTOMAP_FOUND)
ENDIF(WITH_OCTOMAP)
IF(WITH_CPUTSDF)
FIND_PACKAGE(CPUTSDF QUIET)
IF(CPUTSDF_FOUND)
MESSAGE(STATUS "Found CPUTSDF: ${CPUTSDF_INCLUDE_DIRS}")
ENDIF(CPUTSDF_FOUND)
ENDIF(WITH_CPUTSDF)
IF(G2O_FOUND OR GTSAM_FOUND OR ZED_FOUND OR ANDROID OR RealSense_FOUND)
#Newest versions require std11
IF(NOT MSVC)
@@ -453,6 +461,11 @@ IF(NOT OCTOMAP_FOUND)
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${OCTOMAP_LIBRARIES})
ENDIF()
IF(NOT CPUTSDF_FOUND)
SET(CPUTSDF "//")
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${CPUTSDF_LIBRARIES})
ENDIF()
IF(ADD_VTK_GUI_SUPPORT_QT_TO_CONF)
SET(CONF_VTK_QT true)
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} vtkGUISupportQt)
@@ -768,6 +781,14 @@ ELSE()
MESSAGE(STATUS " With OCTOMAP = NO (octomap not found)")
ENDIF()
IF(CPUTSDF_FOUND)
MESSAGE(STATUS " With CPUTSDF = YES (License: BSD)")
ELSEIF(NOT WITH_CPUTSDF)
MESSAGE(STATUS " With CPUTSDF = NO (WITH_CPUTSDF=OFF)")
ELSE()
MESSAGE(STATUS " With CPUTSDF = NO (CPUTSDF not found)")
ENDIF()
IF(QT4_FOUND)
MESSAGE(STATUS " With Qt4 = YES (License: Open Source or Commercial)")
ELSEIF(Qt5_FOUND)
+1
View File
@@ -53,6 +53,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@REALSENSE@#define RTABMAP_REALSENSE
@REALSENSESLAM@#define RTABMAP_REALSENSE_SLAM
@OCTOMAP@#define RTABMAP_OCTOMAP
@CPUTSDF@#define RTABMAP_CPUTSDF
#endif /* VERSION_H_ */
+5
View File
@@ -60,6 +60,11 @@ AboutDialog::AboutDialog(QWidget * parent) :
_ui->label_octomap->setText("Yes");
#else
_ui->label_octomap->setText("No");
#endif
#ifdef RTABMAP_CPUTSDF
_ui->label_cputsdf->setText("Yes");
#else
_ui->label_cputsdf->setText("No");
#endif
_ui->label_freenect->setText(CameraFreenect::available()?"Yes":"No");
_ui->label_openni2->setText(CameraOpenNI2::available()?"Yes":"No");
+11
View File
@@ -137,6 +137,17 @@ IF(OCTOMAP_FOUND)
)
ENDIF(OCTOMAP_FOUND)
IF(CPUTSDF_FOUND)
SET(INCLUDE_DIRS
${INCLUDE_DIRS}
${CPUTSDF_INCLUDE_DIRS}
)
SET(LIBRARIES
${LIBRARIES}
${CPUTSDF_LIBRARIES}
)
ENDIF(CPUTSDF_FOUND)
IF(VTK_USE_QVTK)
SET(INCLUDE_DIRS ${INCLUDE_DIRS} ${QVTK_INCLUDE_DIR})
SET(LIBRARIES ${LIBRARIES} ${QVTK_LIBRARY})
+467 -248
View File
@@ -45,6 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/GainCompensator.h"
#include "rtabmap/core/clams/discrete_depth_distortion_model.h"
#include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/Version.h"
#include <pcl/conversions.h>
#include <pcl/io/pcd_io.h>
@@ -62,6 +63,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QInputDialog>
#include <QDesktopWidget>
#ifdef RTABMAP_CPUTSDF
#include <cpu_tsdf/tsdf_volume_octree.h>
#include <cpu_tsdf/marching_cubes_tsdf_octree.h>
#endif
namespace rtabmap {
ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
@@ -175,6 +181,14 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
connect(_ui->doubleSpinBox_poisson_pointWeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_poisson_scale, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_cputsdf_size, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_cputsdf_resolution, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_cputsdf_tuncPos, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_cputsdf_tuncNeg, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_cputsdf_minWeight, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->doubleSpinBox_cputsdf_flattenRadius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->spinBox_cputsdf_randomSplit, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged()));
_progressDialog = new ProgressDialog(this);
_progressDialog->setVisible(false);
_progressDialog->setAutoClose(true, 2);
@@ -312,6 +326,14 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou
settings.setValue("poisson_pointWeight", _ui->doubleSpinBox_poisson_pointWeight->value());
settings.setValue("poisson_scale", _ui->doubleSpinBox_poisson_scale->value());
settings.setValue("cputsdf_size", _ui->doubleSpinBox_cputsdf_size->value());
settings.setValue("cputsdf_resolution", _ui->doubleSpinBox_cputsdf_resolution->value());
settings.setValue("cputsdf_truncPos", _ui->doubleSpinBox_cputsdf_tuncPos->value());
settings.setValue("cputsdf_truncNeg", _ui->doubleSpinBox_cputsdf_tuncNeg->value());
settings.setValue("cputsdf_minWeight", _ui->doubleSpinBox_cputsdf_minWeight->value());
settings.setValue("cputsdf_flattenRadius", _ui->doubleSpinBox_cputsdf_flattenRadius->value());
settings.setValue("cputsdf_randomSplit", _ui->spinBox_cputsdf_randomSplit->value());
if(!group.isEmpty())
{
settings.endGroup();
@@ -413,6 +435,14 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
_ui->doubleSpinBox_poisson_pointWeight->setValue(settings.value("poisson_pointWeight", _ui->doubleSpinBox_poisson_pointWeight->value()).toDouble());
_ui->doubleSpinBox_poisson_scale->setValue(settings.value("poisson_scale", _ui->doubleSpinBox_poisson_scale->value()).toDouble());
_ui->doubleSpinBox_cputsdf_size->setValue(settings.value("cputsdf_size", _ui->doubleSpinBox_cputsdf_size->value()).toDouble());
_ui->doubleSpinBox_cputsdf_resolution->setValue(settings.value("cputsdf_resolution", _ui->doubleSpinBox_cputsdf_resolution->value()).toDouble());
_ui->doubleSpinBox_cputsdf_tuncPos->setValue(settings.value("cputsdf_truncPos", _ui->doubleSpinBox_cputsdf_tuncPos->value()).toDouble());
_ui->doubleSpinBox_cputsdf_tuncNeg->setValue(settings.value("cputsdf_truncNeg", _ui->doubleSpinBox_cputsdf_tuncNeg->value()).toDouble());
_ui->doubleSpinBox_cputsdf_minWeight->setValue(settings.value("cputsdf_minWeight", _ui->doubleSpinBox_cputsdf_minWeight->value()).toDouble());
_ui->doubleSpinBox_cputsdf_flattenRadius->setValue(settings.value("cputsdf_flattenRadius", _ui->doubleSpinBox_cputsdf_flattenRadius->value()).toDouble());
_ui->spinBox_cputsdf_randomSplit->setValue(settings.value("cputsdf_randomSplit", _ui->spinBox_cputsdf_randomSplit->value()).toInt());
updateReconstructionFlavor();
updateMLSGrpVisibility();
@@ -509,6 +539,14 @@ void ExportCloudsDialog::restoreDefaults()
_ui->doubleSpinBox_poisson_pointWeight->setValue(4.0);
_ui->doubleSpinBox_poisson_scale->setValue(1.1);
_ui->doubleSpinBox_cputsdf_size->setValue(12.0);
_ui->doubleSpinBox_cputsdf_resolution->setValue(0.01);
_ui->doubleSpinBox_cputsdf_tuncPos->setValue(0.03);
_ui->doubleSpinBox_cputsdf_tuncNeg->setValue(0.03);
_ui->doubleSpinBox_cputsdf_minWeight->setValue(0);
_ui->doubleSpinBox_cputsdf_flattenRadius->setValue(0.005);
_ui->spinBox_cputsdf_randomSplit->setValue(1);
updateReconstructionFlavor();
updateMLSGrpVisibility();
@@ -519,14 +557,6 @@ void ExportCloudsDialog::updateReconstructionFlavor()
{
_ui->checkBox_smoothing->setVisible(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->checkBox_smoothing->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->label_denseReconstruction->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
#ifndef DISABLE_VTK
_ui->doubleSpinBox_meshDecimationFactor->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->label_meshDecimation->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->spinBox_meshMaxPolygons->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->label_meshMaxPolygons->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
#endif
_ui->groupBox_organized->setVisible(_ui->comboBox_pipeline->currentIndex() == 0);
_ui->groupBox_regenerate->setVisible(_ui->checkBox_regenerate->isChecked());
_ui->groupBox_bilateral->setVisible(_ui->checkBox_bilateral->isChecked());
@@ -539,15 +569,28 @@ void ExportCloudsDialog::updateReconstructionFlavor()
_ui->groupBox_cameraFilter->setVisible(_ui->checkBox_cameraFilter->isChecked());
// dense texturing options
_ui->groupBox_gp3->setVisible(_ui->comboBox_pipeline->currentIndex() == 1 && _ui->comboBox_meshingApproach->currentIndex()==0);
_ui->groupBox_poisson->setVisible(_ui->comboBox_pipeline->currentIndex() == 1 && _ui->comboBox_meshingApproach->currentIndex()==1);
if(_ui->checkBox_meshing->isChecked())
{
_ui->comboBox_meshingApproach->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->comboBox_meshingApproach->setItemData(1, _ui->checkBox_assemble->isChecked()?1 | 32:0,Qt::UserRole - 1);
_ui->comboBox_meshingApproach->setItemData(0, _ui->comboBox_pipeline->currentIndex() == 1?1 | 32:0,Qt::UserRole - 1);
_ui->comboBox_meshingApproach->setItemData(1, _ui->comboBox_pipeline->currentIndex() == 1 && _ui->checkBox_assemble->isChecked()?1 | 32:0,Qt::UserRole - 1);
#ifdef RTABMAP_CPUTSDF
_ui->comboBox_meshingApproach->setItemData(2, _ui->comboBox_pipeline->currentIndex() == 0 && _ui->checkBox_assemble->isChecked()?1 | 32:0,Qt::UserRole - 1);
#else
_ui->comboBox_meshingApproach->setItemData(2, Qt::UserRole - 1);
#endif
_ui->comboBox_meshingApproach->setItemData(3, _ui->comboBox_pipeline->currentIndex() == 0?1 | 32:0,Qt::UserRole - 1);
if(_ui->comboBox_pipeline->currentIndex() == 0 && _ui->comboBox_meshingApproach->currentIndex()<2)
{
_ui->comboBox_meshingApproach->setCurrentIndex(3);
}
if(_ui->comboBox_pipeline->currentIndex() == 1 && _ui->comboBox_meshingApproach->currentIndex()>1)
{
_ui->comboBox_meshingApproach->setCurrentIndex(1);
}
if(!_ui->checkBox_assemble->isChecked())
{
_ui->comboBox_meshingApproach->setCurrentIndex(0);
_ui->comboBox_meshingApproach->setCurrentIndex(_ui->comboBox_pipeline->currentIndex() == 1?0:3);
}
_ui->checkBox_poisson_outputPolygons->setDisabled(
@@ -558,6 +601,18 @@ void ExportCloudsDialog::updateReconstructionFlavor()
_ui->checkBox_cleanMesh->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->label_meshClean->setEnabled(_ui->comboBox_pipeline->currentIndex() == 1);
_ui->groupBox_gp3->setVisible(_ui->comboBox_pipeline->currentIndex() == 1 && _ui->comboBox_meshingApproach->currentIndex()==0);
_ui->groupBox_poisson->setVisible(_ui->comboBox_pipeline->currentIndex() == 1 && _ui->comboBox_meshingApproach->currentIndex()==1);
_ui->groupBox_cputsdf->setVisible(_ui->comboBox_pipeline->currentIndex() == 0 && _ui->comboBox_meshingApproach->currentIndex()==2);
_ui->groupBox_organized->setVisible(_ui->comboBox_pipeline->currentIndex() == 0 && _ui->comboBox_meshingApproach->currentIndex()==3);
#ifndef DISABLE_VTK
_ui->doubleSpinBox_meshDecimationFactor->setEnabled(_ui->comboBox_meshingApproach->currentIndex()!=3);
_ui->label_meshDecimation->setEnabled(_ui->comboBox_meshingApproach->currentIndex()!=3);
_ui->spinBox_meshMaxPolygons->setEnabled(_ui->comboBox_meshingApproach->currentIndex()!=3);
_ui->label_meshMaxPolygons->setEnabled(_ui->comboBox_meshingApproach->currentIndex()!=3);
#endif
}
}
@@ -1255,6 +1310,10 @@ bool ExportCloudsDialog::getExportedClouds(
}
}
#ifdef RTABMAP_CPUTSDF
cpu_tsdf::TSDFVolumeOctree::Ptr tsdf;
#endif
//used for organized texturing below
std::map<int, std::vector<int> > organizedIndices;
std::map<int, cv::Size> organizedCloudSizes;
@@ -1264,8 +1323,15 @@ bool ExportCloudsDialog::getExportedClouds(
if(_ui->checkBox_meshing->isChecked())
{
if(_ui->comboBox_pipeline->currentIndex() == 0)
{
if(_ui->comboBox_meshingApproach->currentIndex()==2)
{
_progressDialog->appendText(tr("Creating TSDF volume... "));
}
else
{
_progressDialog->appendText(tr("Organized fast mesh... "));
}
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
@@ -1297,6 +1363,65 @@ bool ExportCloudsDialog::getExportedClouds(
_dbDriver->getCalibration(iter->first, models, stereoModel);
}
#ifdef RTABMAP_CPUTSDF
if(_ui->comboBox_meshingApproach->currentIndex()==2 && _ui->checkBox_assemble->isChecked())
{
if(tsdf.get() == 0)
{
if(models.size()==1 && models[0].isValidForProjection() && models[0].imageHeight()>0 && models[0].imageWidth()>0)
{
float tsdf_size = _ui->doubleSpinBox_cputsdf_size->value();
float cell_size = _ui->doubleSpinBox_cputsdf_resolution->value();
int num_random_splits = _ui->spinBox_cputsdf_randomSplit->value();
int tsdf_res;
int desired_res = tsdf_size / cell_size;
// Snap to nearest power of 2;
int n = 1;
while (desired_res > n)
{
n *= 2;
}
tsdf_res = n;
_progressDialog->appendText(tr("CPU-TSDF: Setting resolution: %1 with grid size %2").arg(tsdf_res).arg(tsdf_size));
tsdf.reset (new cpu_tsdf::TSDFVolumeOctree);
tsdf->setGridSize (tsdf_size, tsdf_size, tsdf_size);
tsdf->setResolution (tsdf_res, tsdf_res, tsdf_res);
float decimation = float(models[0].imageWidth()) / float(iter->second->width);
tsdf->setImageSize (models[0].imageWidth()/decimation, models[0].imageHeight()/decimation);
tsdf->setCameraIntrinsics (models[0].fx()/decimation, models[0].fy()/decimation, models[0].cx()/decimation, models[0].cy()/decimation);
tsdf->setNumRandomSplts (num_random_splits);
tsdf->setSensorDistanceBounds (0, 9999);
tsdf->setIntegrateColor(true);
tsdf->setDepthTruncationLimits (_ui->doubleSpinBox_cputsdf_tuncPos->value(), _ui->doubleSpinBox_cputsdf_tuncNeg->value());
tsdf->reset ();
}
else
{
_progressDialog->appendText(tr("CPU-TSDF: Invalid camera model! Only single RGB-D camera supported."), Qt::darkYellow);
_progressDialog->setAutoClose(false);
break;
}
}
if(tsdf.get())
{
if(tsdf.get() && models.size() == 1 && !models[0].localTransform().isNull())
{
Eigen::Affine3d pose_rel_to_first_frame = ((poses.begin()->second.inverse() * poses.at(iter->first))*models[0].localTransform()).toEigen3d();
if(!tsdf->integrateCloud(*util3d::transformPointCloud(iter->second, models[0].localTransform().inverse()), pcl::PointCloud<pcl::Normal>(), pose_rel_to_first_frame))
{
_progressDialog->appendText(tr("CPU-TSDF: Failed integrating cloud %1 to TSDF volume").arg(iter->first));
}
else
{
_progressDialog->appendText(tr("CPU-TSDF: Integrated cloud %1 to TSDF volume").arg(iter->first));
}
}
}
}
else
#endif
{
if(models.size() && !models[0].localTransform().isNull())
{
viewpoint[0] = models[0].localTransform().x();
@@ -1422,6 +1547,7 @@ bool ExportCloudsDialog::getExportedClouds(
}
}
}
}
else
{
_progressDialog->appendText(tr("Mesh %1 not created (no valid points) (%2/%3).").arg(iter->first).arg(++i).arg(clouds.size()));
@@ -1529,241 +1655,7 @@ bool ExportCloudsDialog::getExportedClouds(
if(mesh->polygons.size()>0)
{
double meshDecimationFactor = 0.0;
if(_ui->doubleSpinBox_meshDecimationFactor->isEnabled() &&
_ui->doubleSpinBox_meshDecimationFactor->value() > 0.0)
{
meshDecimationFactor = _ui->doubleSpinBox_meshDecimationFactor->value();
}
if(_ui->spinBox_meshMaxPolygons->isEnabled() &&
_ui->spinBox_meshMaxPolygons->value() > 0)
{
double factor = 1.0-double(_ui->spinBox_meshMaxPolygons->value())/double(mesh->polygons.size());
if(factor > meshDecimationFactor)
{
meshDecimationFactor = factor;
}
}
if(meshDecimationFactor > 0.0)
{
unsigned int count = mesh->polygons.size();
_progressDialog->appendText(tr("Mesh decimation (factor=%1) from %2 polygons...").arg(meshDecimationFactor).arg(count));
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
mesh = util3d::meshDecimation(mesh, (float)meshDecimationFactor);
_progressDialog->appendText(tr("Mesh decimated (factor=%1) from %2 to %3 polygons").arg(meshDecimationFactor).arg(count).arg(mesh->polygons.size()));
if(count < mesh->polygons.size())
{
_progressDialog->appendText(tr("Decimated mesh %1 has more polygons than before!").arg(iter->first), Qt::darkYellow);
_progressDialog->setAutoClose(false);
}
QApplication::processEvents();
lostColors = true;
}
if(lostColors &&
_ui->doubleSpinBox_transferColorRadius->value() >= 0.0 &&
(!_ui->checkBox_textureMapping->isEnabled() || !_ui->checkBox_textureMapping->isChecked()))
{
_progressDialog->appendText(tr("Transferring color from point cloud to mesh..."));
QApplication::processEvents();
// transfer color from point cloud to mesh
pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGBNormal>(true));
tree->setInputCloud(iter->second);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr coloredCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::fromPCLPointCloud2(mesh->cloud, *coloredCloud);
std::vector<bool> coloredPts(coloredCloud->size());
for(unsigned int i=0; i<coloredCloud->size(); ++i)
{
std::vector<int> kIndices;
std::vector<float> kDistances;
pcl::PointXYZRGBNormal pt;
pt.x = coloredCloud->at(i).x;
pt.y = coloredCloud->at(i).y;
pt.z = coloredCloud->at(i).z;
if(_ui->doubleSpinBox_transferColorRadius->value() > 0.0)
{
tree->radiusSearch(pt, _ui->doubleSpinBox_transferColorRadius->value(), kIndices, kDistances);
}
else
{
tree->nearestKSearch(pt, 1, kIndices, kDistances);
}
if(kIndices.size())
{
//compute average color
int r=0;
int g=0;
int b=0;
int a=0;
for(unsigned int j=0; j<kIndices.size(); ++j)
{
r+=(int)iter->second->at(kIndices[j]).r;
g+=(int)iter->second->at(kIndices[j]).g;
b+=(int)iter->second->at(kIndices[j]).b;
a+=(int)iter->second->at(kIndices[j]).a;
}
coloredCloud->at(i).r = r/kIndices.size();
coloredCloud->at(i).g = g/kIndices.size();
coloredCloud->at(i).b = b/kIndices.size();
coloredCloud->at(i).a = a/kIndices.size();
coloredPts.at(i) = true;
}
else
{
//white
coloredCloud->at(i).r = coloredCloud->at(i).g = coloredCloud->at(i).b = 255;
coloredPts.at(i) = false;
}
}
pcl::toPCLPointCloud2(*coloredCloud, mesh->cloud);
// remove polygons with no color
if(_ui->checkBox_cleanMesh->isChecked())
{
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
int oi=0;
for(unsigned int i=0; i<mesh->polygons.size(); ++i)
{
bool coloredPolygon = true;
for(unsigned int j=0; j<mesh->polygons[i].vertices.size(); ++j)
{
if(!coloredPts.at(mesh->polygons[i].vertices[j]))
{
coloredPolygon = false;
break;
}
}
if(coloredPolygon)
{
filteredPolygons[oi++] = mesh->polygons[i];
}
}
filteredPolygons.resize(oi);
mesh->polygons = filteredPolygons;
}
}
else if(lostColors &&
_ui->doubleSpinBox_transferColorRadius->value() > 0.0 &&
_ui->checkBox_cleanMesh->isChecked() &&
(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()))
{
_progressDialog->appendText(tr("Removing polygons too far from the cloud..."));
QApplication::processEvents();
// transfer color from point cloud to mesh
pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGBNormal>(true));
tree->setInputCloud(iter->second);
pcl::PointCloud<pcl::PointXYZ>::Ptr optimizedCloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::fromPCLPointCloud2(mesh->cloud, *optimizedCloud);
std::vector<bool> closePts(optimizedCloud->size());
for(unsigned int i=0; i<optimizedCloud->size(); ++i)
{
std::vector<int> kIndices;
std::vector<float> kDistances;
pcl::PointXYZRGBNormal pt;
pt.x = optimizedCloud->at(i).x;
pt.y = optimizedCloud->at(i).y;
pt.z = optimizedCloud->at(i).z;
tree->radiusSearch(pt, _ui->doubleSpinBox_transferColorRadius->value(), kIndices, kDistances);
if(kIndices.size())
{
closePts.at(i) = true;
}
else
{
closePts.at(i) = false;
}
}
// remove far polygons
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
int oi=0;
for(unsigned int i=0; i<mesh->polygons.size(); ++i)
{
bool keepPolygon = true;
for(unsigned int j=0; j<mesh->polygons[i].vertices.size(); ++j)
{
if(!closePts.at(mesh->polygons[i].vertices[j]))
{
keepPolygon = false;
break;
}
}
if(keepPolygon)
{
filteredPolygons[oi++] = mesh->polygons[i];
}
}
filteredPolygons.resize(oi);
mesh->polygons = filteredPolygons;
}
if(_ui->spinBox_mesh_minClusterSize->value() &&
!(_ui->checkBox_textureMapping->isEnabled() &&
_ui->checkBox_textureMapping->isChecked() &&
_ui->checkBox_cleanMesh->isChecked()))
{
_progressDialog->appendText(tr("Filter small polygon clusters..."));
QApplication::processEvents();
// filter polygons
std::vector<std::set<int> > neighbors;
std::vector<std::set<int> > vertexToPolygons;
util3d::createPolygonIndexes(mesh->polygons,
mesh->cloud.height*mesh->cloud.width,
neighbors,
vertexToPolygons);
std::list<std::list<int> > clusters = util3d::clusterPolygons(
neighbors,
_ui->spinBox_mesh_minClusterSize->value()<0?0:_ui->spinBox_mesh_minClusterSize->value());
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
if(_ui->spinBox_mesh_minClusterSize->value() < 0)
{
// only keep the biggest cluster
std::list<std::list<int> >::iterator biggestClusterIndex = clusters.end();
unsigned int biggestClusterSize = 0;
for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
{
if(iter->size() > biggestClusterSize)
{
biggestClusterIndex = iter;
biggestClusterSize = iter->size();
}
}
if(biggestClusterIndex != clusters.end())
{
int oi=0;
for(std::list<int>::iterator jter=biggestClusterIndex->begin(); jter!=biggestClusterIndex->end(); ++jter)
{
filteredPolygons[oi++] = mesh->polygons.at(*jter);
}
filteredPolygons.resize(oi);
}
}
else
{
int oi=0;
for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
{
for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
{
filteredPolygons[oi++] = mesh->polygons.at(*jter);
}
}
filteredPolygons.resize(oi);
}
int before = (int)mesh->polygons.size();
mesh->polygons = filteredPolygons;
_progressDialog->appendText(tr("Filtered %1 polygons.").arg(before-(int)mesh->polygons.size()));
}
denseMeshPostProcessing(iter->first, mesh, lostColors, iter->second);
meshes.insert(std::make_pair(iter->first, mesh));
}
else
@@ -1782,6 +1674,91 @@ bool ExportCloudsDialog::getExportedClouds(
}
}
#ifdef RTABMAP_CPUTSDF
if(tsdf.get())
{
_progressDialog->appendText(tr("CPU-TSDF: Creating mesh from TSDF volume..."));
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
cpu_tsdf::MarchingCubesTSDFOctree mc;
mc.setMinWeight (_ui->doubleSpinBox_cputsdf_minWeight->value());
mc.setInputTSDF (tsdf);
mc.setColorByRGB (true);
pcl::PolygonMesh::Ptr mesh (new pcl::PolygonMesh);
mc.reconstruct (*mesh);
_progressDialog->appendText(tr("CPU-TSDF: Creating mesh from TSDF volume...done!"));
meshes.clear();
if(mesh->polygons.size()>0)
{
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr vertices (new pcl::PointCloud<pcl::PointXYZRGBNormal>);
pcl::fromPCLPointCloud2 (mesh->cloud, *vertices);
if(_ui->doubleSpinBox_cputsdf_flattenRadius->value()>0.0)
{
_progressDialog->appendText(tr("CPU-TSDF: Flattening mesh (radius=%1)...").arg(_ui->doubleSpinBox_cputsdf_flattenRadius->value()));
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
float min_dist = _ui->doubleSpinBox_cputsdf_flattenRadius->value();
pcl::search::KdTree<pcl::PointXYZRGBNormal> vert_tree (true);
vert_tree.setInputCloud (vertices);
// Find duplicates
std::vector<int> vertex_remap (vertices->size (), -1);
int idx = 0;
std::vector<int> neighbors;
std::vector<float> dists;
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr vertices_new(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
vertices_new->resize(vertices->size ());
for (size_t i = 0; i < vertices->size (); i++)
{
if (vertex_remap[i] >= 0)
continue;
vertex_remap[i] = idx;
vert_tree.radiusSearch (i, min_dist, neighbors, dists);
for (size_t j = 1; j < neighbors.size (); j++)
{
if (dists[j] < min_dist)
vertex_remap[neighbors[j]] = idx;
}
vertices_new->at(idx++) = vertices->at (i);
}
vertices_new->resize(idx);
std::vector<size_t> faces_to_remove;
size_t face_idx = 0;
for (size_t i = 0; i < mesh->polygons.size (); i++)
{
pcl::Vertices &v = mesh->polygons[i];
for (size_t j = 0; j < v.vertices.size (); j++)
{
v.vertices[j] = vertex_remap[v.vertices[j]];
}
if (!(v.vertices[0] == v.vertices[1] || v.vertices[1] == v.vertices[2] || v.vertices[2] == v.vertices[0]))
{
mesh->polygons[face_idx++] = mesh->polygons[i];
}
}
mesh->polygons.resize (face_idx);
pcl::toPCLPointCloud2 (*vertices_new, mesh->cloud);
vertices = vertices_new;
}
pcl::fromPCLPointCloud2(mesh->cloud, *vertices);
denseMeshPostProcessing(0, mesh, false, vertices);
meshes.insert(std::make_pair(0, mesh));
}
else
{
_progressDialog->appendText(tr("No polygons created TSDF volume!"), Qt::darkYellow);
_progressDialog->setAutoClose(false);
}
}
#endif
if(_canceled)
{
return false;
@@ -3628,4 +3605,246 @@ void ExportCloudsDialog::saveTextureMeshes(
}
}
void ExportCloudsDialog::denseMeshPostProcessing(
int id,
pcl::PolygonMeshPtr & mesh,
bool lostColors,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud)
{
double meshDecimationFactor = 0.0;
if(_ui->doubleSpinBox_meshDecimationFactor->isEnabled() &&
_ui->doubleSpinBox_meshDecimationFactor->value() > 0.0)
{
meshDecimationFactor = _ui->doubleSpinBox_meshDecimationFactor->value();
}
if(_ui->spinBox_meshMaxPolygons->isEnabled() &&
_ui->spinBox_meshMaxPolygons->value() > 0)
{
double factor = 1.0-double(_ui->spinBox_meshMaxPolygons->value())/double(mesh->polygons.size());
if(factor > meshDecimationFactor)
{
meshDecimationFactor = factor;
}
}
if(meshDecimationFactor > 0.0)
{
unsigned int count = mesh->polygons.size();
_progressDialog->appendText(tr("Mesh decimation (factor=%1) from %2 polygons...").arg(meshDecimationFactor).arg(count));
QApplication::processEvents();
uSleep(100);
QApplication::processEvents();
mesh = util3d::meshDecimation(mesh, (float)meshDecimationFactor);
_progressDialog->appendText(tr("Mesh decimated (factor=%1) from %2 to %3 polygons").arg(meshDecimationFactor).arg(count).arg(mesh->polygons.size()));
if(count < mesh->polygons.size())
{
_progressDialog->appendText(tr("Decimated mesh %1 has more polygons than before!").arg(id), Qt::darkYellow);
_progressDialog->setAutoClose(false);
}
QApplication::processEvents();
lostColors = true;
}
if(lostColors &&
_ui->doubleSpinBox_transferColorRadius->value() >= 0.0 &&
(!_ui->checkBox_textureMapping->isEnabled() || !_ui->checkBox_textureMapping->isChecked()))
{
_progressDialog->appendText(tr("Transferring color from point cloud to mesh..."));
QApplication::processEvents();
// transfer color from point cloud to mesh
pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGBNormal>(true));
tree->setInputCloud(cloud);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr coloredCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::fromPCLPointCloud2(mesh->cloud, *coloredCloud);
std::vector<bool> coloredPts(coloredCloud->size());
for(unsigned int i=0; i<coloredCloud->size(); ++i)
{
std::vector<int> kIndices;
std::vector<float> kDistances;
pcl::PointXYZRGBNormal pt;
pt.x = coloredCloud->at(i).x;
pt.y = coloredCloud->at(i).y;
pt.z = coloredCloud->at(i).z;
if(_ui->doubleSpinBox_transferColorRadius->value() > 0.0)
{
tree->radiusSearch(pt, _ui->doubleSpinBox_transferColorRadius->value(), kIndices, kDistances);
}
else
{
tree->nearestKSearch(pt, 1, kIndices, kDistances);
}
if(kIndices.size())
{
//compute average color
int r=0;
int g=0;
int b=0;
int a=0;
for(unsigned int j=0; j<kIndices.size(); ++j)
{
r+=(int)cloud->at(kIndices[j]).r;
g+=(int)cloud->at(kIndices[j]).g;
b+=(int)cloud->at(kIndices[j]).b;
a+=(int)cloud->at(kIndices[j]).a;
}
coloredCloud->at(i).r = r/kIndices.size();
coloredCloud->at(i).g = g/kIndices.size();
coloredCloud->at(i).b = b/kIndices.size();
coloredCloud->at(i).a = a/kIndices.size();
coloredPts.at(i) = true;
}
else
{
//white
coloredCloud->at(i).r = coloredCloud->at(i).g = coloredCloud->at(i).b = 255;
coloredPts.at(i) = false;
}
}
pcl::toPCLPointCloud2(*coloredCloud, mesh->cloud);
// remove polygons with no color
if(_ui->checkBox_cleanMesh->isChecked())
{
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
int oi=0;
for(unsigned int i=0; i<mesh->polygons.size(); ++i)
{
bool coloredPolygon = true;
for(unsigned int j=0; j<mesh->polygons[i].vertices.size(); ++j)
{
if(!coloredPts.at(mesh->polygons[i].vertices[j]))
{
coloredPolygon = false;
break;
}
}
if(coloredPolygon)
{
filteredPolygons[oi++] = mesh->polygons[i];
}
}
filteredPolygons.resize(oi);
mesh->polygons = filteredPolygons;
}
}
else if(lostColors &&
_ui->doubleSpinBox_transferColorRadius->value() > 0.0 &&
_ui->checkBox_cleanMesh->isChecked() &&
(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()))
{
_progressDialog->appendText(tr("Removing polygons too far from the cloud..."));
QApplication::processEvents();
// transfer color from point cloud to mesh
pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGBNormal>(true));
tree->setInputCloud(cloud);
pcl::PointCloud<pcl::PointXYZ>::Ptr optimizedCloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::fromPCLPointCloud2(mesh->cloud, *optimizedCloud);
std::vector<bool> closePts(optimizedCloud->size());
for(unsigned int i=0; i<optimizedCloud->size(); ++i)
{
std::vector<int> kIndices;
std::vector<float> kDistances;
pcl::PointXYZRGBNormal pt;
pt.x = optimizedCloud->at(i).x;
pt.y = optimizedCloud->at(i).y;
pt.z = optimizedCloud->at(i).z;
tree->radiusSearch(pt, _ui->doubleSpinBox_transferColorRadius->value(), kIndices, kDistances);
if(kIndices.size())
{
closePts.at(i) = true;
}
else
{
closePts.at(i) = false;
}
}
// remove far polygons
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
int oi=0;
for(unsigned int i=0; i<mesh->polygons.size(); ++i)
{
bool keepPolygon = true;
for(unsigned int j=0; j<mesh->polygons[i].vertices.size(); ++j)
{
if(!closePts.at(mesh->polygons[i].vertices[j]))
{
keepPolygon = false;
break;
}
}
if(keepPolygon)
{
filteredPolygons[oi++] = mesh->polygons[i];
}
}
filteredPolygons.resize(oi);
mesh->polygons = filteredPolygons;
}
if(_ui->spinBox_mesh_minClusterSize->value() &&
!(_ui->checkBox_textureMapping->isEnabled() &&
_ui->checkBox_textureMapping->isChecked() &&
_ui->checkBox_cleanMesh->isChecked()))
{
_progressDialog->appendText(tr("Filter small polygon clusters..."));
QApplication::processEvents();
// filter polygons
std::vector<std::set<int> > neighbors;
std::vector<std::set<int> > vertexToPolygons;
util3d::createPolygonIndexes(mesh->polygons,
mesh->cloud.height*mesh->cloud.width,
neighbors,
vertexToPolygons);
std::list<std::list<int> > clusters = util3d::clusterPolygons(
neighbors,
_ui->spinBox_mesh_minClusterSize->value()<0?0:_ui->spinBox_mesh_minClusterSize->value());
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
if(_ui->spinBox_mesh_minClusterSize->value() < 0)
{
// only keep the biggest cluster
std::list<std::list<int> >::iterator biggestClusterIndex = clusters.end();
unsigned int biggestClusterSize = 0;
for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
{
if(iter->size() > biggestClusterSize)
{
biggestClusterIndex = iter;
biggestClusterSize = iter->size();
}
}
if(biggestClusterIndex != clusters.end())
{
int oi=0;
for(std::list<int>::iterator jter=biggestClusterIndex->begin(); jter!=biggestClusterIndex->end(); ++jter)
{
filteredPolygons[oi++] = mesh->polygons.at(*jter);
}
filteredPolygons.resize(oi);
}
}
else
{
int oi=0;
for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
{
for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
{
filteredPolygons[oi++] = mesh->polygons.at(*jter);
}
}
filteredPolygons.resize(oi);
}
int before = (int)mesh->polygons.size();
mesh->polygons = filteredPolygons;
_progressDialog->appendText(tr("Filtered %1 polygons.").arg(before-(int)mesh->polygons.size()));
}
}
}
+6
View File
@@ -122,6 +122,12 @@ private:
void setOkButton();
void enableRegeneration(bool enabled);
void denseMeshPostProcessing(
int id,
pcl::PolygonMeshPtr & mesh,
bool lostColors,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud);
private:
Ui_ExportCloudsDialog * _ui;
ProgressDialog * _progressDialog;
+180 -163
View File
@@ -82,30 +82,6 @@ p, li { white-space: pre-wrap; }
</item>
<item>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<item row="9" column="1">
<widget class="QLabel" name="label_pcl_version">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Author :</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>With Freenect :</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
@@ -113,8 +89,8 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_freenect">
<item row="9" column="1">
<widget class="QLabel" name="label_pcl_version">
<property name="text">
<string/>
</property>
@@ -123,44 +99,6 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_openni2">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>With Freenect2 :</string>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>With stereo FlyCapture2 :</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>PCL version :</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Version :</string>
</property>
</widget>
</item>
<item row="20" column="1">
<widget class="QLabel" name="label_cvsba">
<property name="text">
@@ -171,15 +109,8 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="19" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>With GTSAM :</string>
</property>
</widget>
</item>
<item row="21" column="1">
<widget class="QLabel" name="label_octomap">
<item row="11" column="1">
<widget class="QLabel" name="label_freenect">
<property name="text">
<string/>
</property>
@@ -188,25 +119,8 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="label_zed">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="21" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>With Octomap :</string>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_dc1394">
<item row="19" column="1">
<widget class="QLabel" name="label_gtsam">
<property name="text">
<string/>
</property>
@@ -225,8 +139,8 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_version">
<item row="21" column="1">
<widget class="QLabel" name="label_octomap">
<property name="text">
<string/>
</property>
@@ -235,41 +149,51 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_HomePage_3">
<item row="13" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://introlab.github.io/rtabmap&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Home page&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>With Freenect2 :</string>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>With OpenNI2 :</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_vtk_version">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_openni2">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_7">
<item row="9" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>OpenCV version :</string>
<string>PCL version :</string>
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QLabel" name="label_14">
<item row="17" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>With g2o :</string>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>With stereo dc1394 :</string>
<string>With stereo Zed :</string>
</property>
</widget>
</item>
@@ -283,42 +207,46 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_8">
<item row="18" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Mathieu Labbé, [email protected]</string>
<string>With g2o :</string>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="label_zed">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_13">
<item row="20" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>With OpenNI2 :</string>
<string>With cvsba :</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_HomePage_2">
<item row="8" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://github.com/introlab/rtabmap&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Source page&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
<string>OpenCV version :</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_opencv_version">
<item row="15" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>With stereo dc1394 :</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_version">
<property name="text">
<string/>
</property>
@@ -337,30 +265,6 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>With stereo Zed :</string>
</property>
</widget>
</item>
<item row="19" column="1">
<widget class="QLabel" name="label_gtsam">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="20" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>With cvsba :</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
@@ -378,6 +282,64 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Mathieu Labbé, [email protected]</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Version :</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_opencv_version">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>With Freenect :</string>
</property>
</widget>
</item>
<item row="21" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>With Octomap :</string>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_dc1394">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Author :</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
@@ -385,8 +347,63 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_vtk_version">
<item row="16" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>With stereo FlyCapture2 :</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_HomePage_2">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://github.com/introlab/rtabmap&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Source page&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_HomePage_3">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://introlab.github.io/rtabmap&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Home page&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="19" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>With GTSAM :</string>
</property>
</widget>
</item>
<item row="22" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>With CPU-TSDF :</string>
</property>
</widget>
</item>
<item row="22" column="1">
<widget class="QLabel" name="label_cputsdf">
<property name="text">
<string/>
</property>
+264 -4
View File
@@ -23,9 +23,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-1802</y>
<y>-3080</y>
<width>778</width>
<height>3385</height>
<height>3701</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
@@ -1205,7 +1205,7 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
<item row="0" column="1">
<widget class="QLabel" name="label_denseReconstruction">
<property name="text">
<string>Surface reconstruction approach. Can be used only when dense reconstruction flavor is selected. Poisson is available when clouds are assembled.</string>
<string>Surface reconstruction approach. Poisson is available when clouds are assembled and dense reconstruction flavor is selected. CPU-TSDF is available when clouds are assembled, organized reconstruction flavor is selected and RTAB-Map is built with CPU-TSDF support.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -1244,7 +1244,7 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
<item row="1" column="1">
<widget class="QLabel" name="label_meshDecimation">
<property name="text">
<string>Mesh quadric decimation factor (0=no decimation). Used to reduce the number of polygons. Higher the factor, lower the output resolution (less polygons). Can be used when dense reconstruction flavor is selected. Can reduce a lot texturing time.</string>
<string>Mesh quadric decimation factor (0=no decimation). Used to reduce the number of polygons. Higher the factor, lower the output resolution (less polygons). Can be used when organized mesh approach is not selected. Can reduce a lot texturing time.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -1273,6 +1273,16 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
<string>Poisson</string>
</property>
</item>
<item>
<property name="text">
<string>CPU-TSDF</string>
</property>
</item>
<item>
<property name="text">
<string>Organized</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
@@ -1998,6 +2008,247 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_cputsdf">
<property name="title">
<string>CPU-TSDF Reconstruction</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_17">
<item>
<widget class="QLabel" name="label_25">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/sdmiller/cpu_tsdf&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://github.com/sdmiller/cpu_tsdf&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_17" columnstretch="0,1">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_cputsdf_size">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.100000000000000</double>
</property>
<property name="maximum">
<double>9999.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>12.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Volume size.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_cputsdf_resolution">
<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>99.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Resolution.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_cputsdf_tuncPos">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.030000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Depth truncation positive limit. Maximum distance a voxel will be set to positive.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_cputsdf_tuncNeg">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.030000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Depth truncation negative limit. Maximum distance a voxel will be set to negative.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QSpinBox" name="spinBox_cputsdf_randomSplit">
<property name="suffix">
<string/>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>99</number>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Set the number of random samples per surface point the octree should split on. If you don't know what this does, it's almost certainly best to leave it at 1.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_cputsdf_minWeight">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>99.000000000000000</double>
</property>
<property name="singleStep">
<double>0.500000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Minimum weight of a voxel to be added in the mesh.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_cputsdf_flattenRadius">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.005000000000000</double>
</property>
<property name="value">
<double>0.005000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Flatten radius (0=disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_organized">
<property name="title">
@@ -2009,6 +2260,9 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
<property name="text">
<string>Triangle size</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
@@ -2016,6 +2270,9 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
<property name="text">
<string>Quad</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
@@ -2052,6 +2309,9 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
<property name="text">
<string>Angle tolerance</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">