mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-03 01:50:24 +08:00
GUI export: added mesh quadric decimation factor option
This commit is contained in:
@@ -84,6 +84,8 @@ void RTABMAP_EXP adjustNormalsToViewPoints(
|
|||||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||||
int k = 0); // optional: recompute normal with k neighbors (min k=3)
|
int k = 0); // optional: recompute normal with k neighbors (min k=3)
|
||||||
|
|
||||||
|
pcl::PolygonMesh::Ptr RTABMAP_EXP meshDecimation(const pcl::PolygonMesh::Ptr & mesh, float factor);
|
||||||
|
|
||||||
template<typename pointT>
|
template<typename pointT>
|
||||||
std::vector<pcl::Vertices> normalizePolygonsSide(
|
std::vector<pcl::Vertices> normalizePolygonsSide(
|
||||||
const pcl::PointCloud<pointT> & cloud,
|
const pcl::PointCloud<pointT> & cloud,
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <pcl/features/normal_3d.h>
|
#include <pcl/features/normal_3d.h>
|
||||||
#include <pcl/surface/mls.h>
|
#include <pcl/surface/mls.h>
|
||||||
#include <pcl/surface/texture_mapping.h>
|
#include <pcl/surface/texture_mapping.h>
|
||||||
|
#include <pcl/surface/vtk_smoothing/vtk_mesh_quadric_decimation.h>
|
||||||
#include <pcl/visualization/pcl_visualizer.h>
|
|
||||||
|
|
||||||
namespace rtabmap
|
namespace rtabmap
|
||||||
{
|
{
|
||||||
@@ -381,6 +380,16 @@ void adjustNormalsToViewPoints(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcl::PolygonMesh::Ptr meshDecimation(const pcl::PolygonMesh::Ptr & mesh, float factor)
|
||||||
|
{
|
||||||
|
pcl::MeshQuadricDecimationVTK mqd;
|
||||||
|
mqd.setTargetReductionFactor(factor);
|
||||||
|
mqd.setInputMesh(mesh);
|
||||||
|
pcl::PolygonMesh::Ptr output(new pcl::PolygonMesh);
|
||||||
|
mqd.process (*output);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,6 +135,12 @@ public:
|
|||||||
const Transform & pose = Transform::getIdentity(),
|
const Transform & pose = Transform::getIdentity(),
|
||||||
const QColor & color = QColor());
|
const QColor & color = QColor());
|
||||||
|
|
||||||
|
bool addCloudMesh(
|
||||||
|
const std::string & id,
|
||||||
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||||
|
const std::vector<pcl::Vertices> & polygons,
|
||||||
|
const Transform & pose = Transform::getIdentity());
|
||||||
|
|
||||||
bool addCloudMesh(
|
bool addCloudMesh(
|
||||||
const std::string & id,
|
const std::string & id,
|
||||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
|
|||||||
@@ -536,6 +536,25 @@ bool CloudViewer::addCloud(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CloudViewer::addCloudMesh(
|
||||||
|
const std::string & id,
|
||||||
|
const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
|
||||||
|
const std::vector<pcl::Vertices> & polygons,
|
||||||
|
const Transform & pose)
|
||||||
|
{
|
||||||
|
if(!_addedClouds.contains(id))
|
||||||
|
{
|
||||||
|
UDEBUG("Adding %s with %d points and %d polygons", id.c_str(), (int)cloud->size(), (int)polygons.size());
|
||||||
|
if(_visualizer->addPolygonMesh<pcl::PointXYZ>(cloud, polygons, id))
|
||||||
|
{
|
||||||
|
_visualizer->updatePointCloudPose(id, pose.toEigen3f());
|
||||||
|
_addedClouds.insert(id, pose);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CloudViewer::addCloudMesh(
|
bool CloudViewer::addCloudMesh(
|
||||||
const std::string & id,
|
const std::string & id,
|
||||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
|
|||||||
connect(_ui->groupBox_gp3, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
|
connect(_ui->groupBox_gp3, SIGNAL(clicked(bool)), this, SIGNAL(configChanged()));
|
||||||
connect(_ui->doubleSpinBox_gp3Radius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
connect(_ui->doubleSpinBox_gp3Radius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||||
connect(_ui->doubleSpinBox_gp3Mu, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
connect(_ui->doubleSpinBox_gp3Mu, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||||
|
connect(_ui->doubleSpinBox_meshDecimationFactor, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
||||||
connect(_ui->checkBox_textureMapping, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
|
connect(_ui->checkBox_textureMapping, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +118,7 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou
|
|||||||
settings.setValue("mesh", this->getMesh());
|
settings.setValue("mesh", this->getMesh());
|
||||||
settings.setValue("mesh_radius", this->getMeshGp3Radius());
|
settings.setValue("mesh_radius", this->getMeshGp3Radius());
|
||||||
settings.setValue("mesh_mu", this->getMeshGp3Mu());
|
settings.setValue("mesh_mu", this->getMeshGp3Mu());
|
||||||
|
settings.setValue("mesh_decimation_factor", this->getMeshDecimationFactor());
|
||||||
|
|
||||||
settings.setValue("mesh_texture", this->getMeshTexture());
|
settings.setValue("mesh_texture", this->getMeshTexture());
|
||||||
|
|
||||||
@@ -157,6 +159,7 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
|
|||||||
_ui->groupBox_gp3->setChecked(settings.value("mesh", this->getMesh()).toBool());
|
_ui->groupBox_gp3->setChecked(settings.value("mesh", this->getMesh()).toBool());
|
||||||
_ui->doubleSpinBox_gp3Radius->setValue(settings.value("mesh_radius", this->getMeshGp3Radius()).toDouble());
|
_ui->doubleSpinBox_gp3Radius->setValue(settings.value("mesh_radius", this->getMeshGp3Radius()).toDouble());
|
||||||
_ui->doubleSpinBox_gp3Mu->setValue(settings.value("mesh_mu", this->getMeshGp3Mu()).toDouble());
|
_ui->doubleSpinBox_gp3Mu->setValue(settings.value("mesh_mu", this->getMeshGp3Mu()).toDouble());
|
||||||
|
_ui->doubleSpinBox_meshDecimationFactor->setValue(settings.value("mesh_decimation_factor", this->getMeshDecimationFactor()).toDouble());
|
||||||
|
|
||||||
_ui->checkBox_textureMapping->setChecked(settings.value("mesh_texture", this->getGenerate()).toBool());
|
_ui->checkBox_textureMapping->setChecked(settings.value("mesh_texture", this->getGenerate()).toBool());
|
||||||
|
|
||||||
@@ -195,7 +198,10 @@ void ExportCloudsDialog::restoreDefaults()
|
|||||||
_ui->groupBox_gp3->setChecked(false);
|
_ui->groupBox_gp3->setChecked(false);
|
||||||
_ui->doubleSpinBox_gp3Radius->setValue(0.04);
|
_ui->doubleSpinBox_gp3Radius->setValue(0.04);
|
||||||
_ui->doubleSpinBox_gp3Mu->setValue(2.5);
|
_ui->doubleSpinBox_gp3Mu->setValue(2.5);
|
||||||
|
_ui->doubleSpinBox_meshDecimationFactor->setValue(1.0);
|
||||||
_ui->checkBox_textureMapping->setChecked(false);
|
_ui->checkBox_textureMapping->setChecked(false);
|
||||||
|
|
||||||
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportCloudsDialog::setSaveButton()
|
void ExportCloudsDialog::setSaveButton()
|
||||||
@@ -316,6 +322,10 @@ double ExportCloudsDialog::getMeshGp3Mu() const
|
|||||||
{
|
{
|
||||||
return _ui->doubleSpinBox_gp3Mu->value();
|
return _ui->doubleSpinBox_gp3Mu->value();
|
||||||
}
|
}
|
||||||
|
double ExportCloudsDialog::getMeshDecimationFactor() const
|
||||||
|
{
|
||||||
|
return _ui->doubleSpinBox_meshDecimationFactor->value();
|
||||||
|
}
|
||||||
bool ExportCloudsDialog::getMeshTexture() const
|
bool ExportCloudsDialog::getMeshTexture() const
|
||||||
{
|
{
|
||||||
return _ui->checkBox_textureMapping->isChecked();
|
return _ui->checkBox_textureMapping->isChecked();
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public:
|
|||||||
bool getMesh() const;
|
bool getMesh() const;
|
||||||
double getMeshGp3Radius() const;
|
double getMeshGp3Radius() const;
|
||||||
double getMeshGp3Mu() const;
|
double getMeshGp3Mu() const;
|
||||||
|
double getMeshDecimationFactor() const;
|
||||||
bool getMeshTexture() const;
|
bool getMeshTexture() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|||||||
@@ -4495,9 +4495,27 @@ void MainWindow::viewClouds()
|
|||||||
{
|
{
|
||||||
_initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)...").arg(iter->first).arg(iter->second->polygons.size()));
|
_initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)...").arg(iter->first).arg(iter->second->polygons.size()));
|
||||||
_initProgressDialog->incrementStep();
|
_initProgressDialog->incrementStep();
|
||||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
|
bool isRGB = false;
|
||||||
pcl::fromPCLPointCloud2(iter->second->cloud, *cloud);
|
for(unsigned int i=0; i<iter->second->cloud.fields.size(); ++i)
|
||||||
viewer->addCloudMesh(uFormat("mesh%d",iter->first), cloud, iter->second->polygons, iter->first>0?_currentPosesMap.at(iter->first):Transform::getIdentity());
|
{
|
||||||
|
if(iter->second->cloud.fields[i].name.compare("rgb") == 0)
|
||||||
|
{
|
||||||
|
isRGB=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isRGB)
|
||||||
|
{
|
||||||
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||||
|
pcl::fromPCLPointCloud2(iter->second->cloud, *cloud);
|
||||||
|
viewer->addCloudMesh(uFormat("mesh%d",iter->first), cloud, iter->second->polygons, iter->first>0?_currentPosesMap.at(iter->first):Transform::getIdentity());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||||
|
pcl::fromPCLPointCloud2(iter->second->cloud, *cloud);
|
||||||
|
viewer->addCloudMesh(uFormat("mesh%d",iter->first), cloud, iter->second->polygons, iter->first>0?_currentPosesMap.at(iter->first):Transform::getIdentity());
|
||||||
|
}
|
||||||
_initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)... done.").arg(iter->first).arg(iter->second->polygons.size()));
|
_initProgressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)... done.").arg(iter->first).arg(iter->second->polygons.size()));
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
}
|
}
|
||||||
@@ -4684,9 +4702,16 @@ bool MainWindow::getExportedClouds(
|
|||||||
++iter)
|
++iter)
|
||||||
{
|
{
|
||||||
pcl::PolygonMesh::Ptr mesh = util3d::createMesh(iter->second, _exportDialog->getMeshGp3Radius(), _exportDialog->getMeshGp3Mu());
|
pcl::PolygonMesh::Ptr mesh = util3d::createMesh(iter->second, _exportDialog->getMeshGp3Radius(), _exportDialog->getMeshGp3Mu());
|
||||||
|
_initProgressDialog->appendText(tr("Mesh %1 created with %2 polygons (%3/%4).").arg(iter->first).arg(mesh->polygons.size()).arg(++i).arg(clouds.size()));
|
||||||
|
|
||||||
|
if(_exportDialog->getMeshDecimationFactor() < 1.0)
|
||||||
|
{
|
||||||
|
mesh = util3d::meshDecimation(mesh, (float)_exportDialog->getMeshDecimationFactor());
|
||||||
|
_initProgressDialog->appendText(tr("Mesh %1 decimation (factor=%2) to %3 polygons").arg(iter->first).arg(_exportDialog->getMeshDecimationFactor()).arg(mesh->polygons.size()));
|
||||||
|
}
|
||||||
|
|
||||||
meshes.insert(std::make_pair(iter->first, mesh));
|
meshes.insert(std::make_pair(iter->first, mesh));
|
||||||
|
|
||||||
_initProgressDialog->appendText(tr("Mesh %1 created with %2 polygons (%3/%4).").arg(iter->first).arg(mesh->polygons.size()).arg(++i).arg(clouds.size()));
|
|
||||||
_initProgressDialog->incrementStep();
|
_initProgressDialog->incrementStep();
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
}
|
}
|
||||||
@@ -5126,10 +5151,29 @@ void MainWindow::saveMeshes(const std::map<int, pcl::PolygonMesh::Ptr> & meshes,
|
|||||||
{
|
{
|
||||||
pcl::PolygonMesh mesh;
|
pcl::PolygonMesh mesh;
|
||||||
mesh.polygons = iter->second->polygons;
|
mesh.polygons = iter->second->polygons;
|
||||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZRGB>);
|
bool isRGB = false;
|
||||||
pcl::fromPCLPointCloud2(iter->second->cloud, *tmp);
|
for(unsigned int i=0; i<iter->second->cloud.fields.size(); ++i)
|
||||||
tmp = util3d::transformPointCloud(tmp, _currentPosesMap.at(iter->first));
|
{
|
||||||
pcl::toPCLPointCloud2(*tmp, mesh.cloud);
|
if(iter->second->cloud.fields[i].name.compare("rgb") == 0)
|
||||||
|
{
|
||||||
|
isRGB=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isRGB)
|
||||||
|
{
|
||||||
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZRGB>);
|
||||||
|
pcl::fromPCLPointCloud2(iter->second->cloud, *tmp);
|
||||||
|
tmp = util3d::transformPointCloud(tmp, _currentPosesMap.at(iter->first));
|
||||||
|
pcl::toPCLPointCloud2(*tmp, mesh.cloud);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcl::PointCloud<pcl::PointXYZ>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZ>);
|
||||||
|
pcl::fromPCLPointCloud2(iter->second->cloud, *tmp);
|
||||||
|
tmp = util3d::transformPointCloud(tmp, _currentPosesMap.at(iter->first));
|
||||||
|
pcl::toPCLPointCloud2(*tmp, mesh.cloud);
|
||||||
|
}
|
||||||
|
|
||||||
QString pathFile = path+QDir::separator()+QString("%1%2.%3").arg(prefix).arg(iter->first).arg(suffix);
|
QString pathFile = path+QDir::separator()+QString("%1%2.%3").arg(prefix).arg(iter->first).arg(suffix);
|
||||||
bool success =false;
|
bool success =false;
|
||||||
|
|||||||
@@ -23,9 +23,9 @@
|
|||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>-178</y>
|
||||||
<width>766</width>
|
<width>766</width>
|
||||||
<height>915</height>
|
<height>949</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||||
@@ -604,6 +604,16 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
|
|||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1">
|
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1">
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="label_169">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set the multiplier of the nearest neighbor distance to obtain the final search radius for each point (this will make the algorithm adapt to different point densities in the cloud).</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_gp3Radius">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_gp3Radius">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
@@ -634,21 +644,8 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QLabel" name="label_169">
|
|
||||||
<property name="text">
|
|
||||||
<string>Set the multiplier of the nearest neighbor distance to obtain the final search radius for each point (this will make the algorithm adapt to different point densities in the cloud).</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_gp3Mu">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_gp3Mu">
|
||||||
<property name="suffix">
|
|
||||||
<string>0</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
<property name="decimals">
|
||||||
<number>1</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
@@ -666,14 +663,14 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QCheckBox" name="checkBox_textureMapping">
|
<widget class="QCheckBox" name="checkBox_textureMapping">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QLabel" name="label_textureMapping">
|
<widget class="QLabel" name="label_textureMapping">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Texture mapping. Images of the cameras will be projected on the mesh(es). Output is a *.obj format.</string>
|
<string>Texture mapping. Images of the cameras will be projected on the mesh(es). Output is a *.obj format.</string>
|
||||||
@@ -683,6 +680,35 @@ Guidelines: 4 times the voxel size, 0.025 for voxel=0.</string>
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="label_170">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mesh quadric decimation factor (1=no decimation). Used to reduce the number of polygons.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshDecimationFactor">
|
||||||
|
<property name="decimals">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.010000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.100000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user