mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-12 04:29:49 +08:00
ExportCloudsDialog: Updated TextureMesh export. MainWindow: fixed exporting only visible clouds.
This commit is contained in:
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <pcl/point_cloud.h>
|
#include <pcl/point_cloud.h>
|
||||||
#include <pcl/point_types.h>
|
#include <pcl/point_types.h>
|
||||||
#include <pcl/pcl_base.h>
|
#include <pcl/pcl_base.h>
|
||||||
|
#include <pcl/TextureMesh.h>
|
||||||
#include <rtabmap/core/Transform.h>
|
#include <rtabmap/core/Transform.h>
|
||||||
#include <rtabmap/core/SensorData.h>
|
#include <rtabmap/core/SensorData.h>
|
||||||
#include <opencv2/core/core.hpp>
|
#include <opencv2/core/core.hpp>
|
||||||
@@ -201,6 +202,9 @@ pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_EXP concatenateClouds(
|
|||||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP concatenateClouds(
|
pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP concatenateClouds(
|
||||||
const std::list<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & clouds);
|
const std::list<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & clouds);
|
||||||
|
|
||||||
|
pcl::TextureMesh::Ptr RTABMAP_EXP concatenateTextureMeshes(
|
||||||
|
const std::list<pcl::TextureMesh::Ptr> & meshes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Concatenate a vector of indices to a single vector.
|
* @brief Concatenate a vector of indices to a single vector.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1316,6 +1316,65 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr concatenateClouds(const std::list<pcl::Po
|
|||||||
return cloud;
|
return cloud;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcl::TextureMesh::Ptr concatenateTextureMeshes(const std::list<pcl::TextureMesh::Ptr> & meshes)
|
||||||
|
{
|
||||||
|
pcl::TextureMesh::Ptr output(new pcl::TextureMesh);
|
||||||
|
std::map<std::string, int> addedMaterials; //<file, index>
|
||||||
|
for(std::list<pcl::TextureMesh::Ptr>::const_iterator iter = meshes.begin(); iter!=meshes.end(); ++iter)
|
||||||
|
{
|
||||||
|
// append point cloud
|
||||||
|
int polygonStep = output->cloud.height * output->cloud.width;
|
||||||
|
pcl::PCLPointCloud2 tmp;
|
||||||
|
pcl::concatenatePointCloud(output->cloud, iter->get()->cloud, tmp);
|
||||||
|
output->cloud = tmp;
|
||||||
|
|
||||||
|
UASSERT((*iter)->tex_polygons.size() == (*iter)->tex_coordinates.size() &&
|
||||||
|
(*iter)->tex_polygons.size() == (*iter)->tex_materials.size());
|
||||||
|
|
||||||
|
int materialCount = (*iter)->tex_polygons.size();
|
||||||
|
for(int i=0; i<materialCount; ++i)
|
||||||
|
{
|
||||||
|
std::map<std::string, int>::iterator jter = addedMaterials.find((*iter)->tex_materials[i].tex_file);
|
||||||
|
int index;
|
||||||
|
if(jter != addedMaterials.end())
|
||||||
|
{
|
||||||
|
index = jter->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addedMaterials.insert(std::make_pair((*iter)->tex_materials[i].tex_file, output->tex_materials.size()));
|
||||||
|
index = output->tex_materials.size();
|
||||||
|
output->tex_materials.push_back((*iter)->tex_materials[i]);
|
||||||
|
output->tex_materials.back().tex_name = uFormat("material_%d", index);
|
||||||
|
output->tex_polygons.resize(output->tex_polygons.size() + 1);
|
||||||
|
output->tex_coordinates.resize(output->tex_coordinates.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update and append polygon indices
|
||||||
|
int oi = output->tex_polygons[index].size();
|
||||||
|
output->tex_polygons[index].resize(output->tex_polygons[index].size() + (*iter)->tex_polygons[i].size());
|
||||||
|
for(unsigned int j=0; j<(*iter)->tex_polygons[i].size(); ++j)
|
||||||
|
{
|
||||||
|
pcl::Vertices polygon = (*iter)->tex_polygons[i][j];
|
||||||
|
for(unsigned int k=0; k<polygon.vertices.size(); ++k)
|
||||||
|
{
|
||||||
|
polygon.vertices[k] += polygonStep;
|
||||||
|
}
|
||||||
|
output->tex_polygons[index][oi+j] = polygon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append uv coordinates
|
||||||
|
oi = output->tex_coordinates[index].size();
|
||||||
|
output->tex_coordinates[index].resize(output->tex_coordinates[index].size() + (*iter)->tex_coordinates[i].size());
|
||||||
|
for(unsigned int j=0; j<(*iter)->tex_coordinates[i].size(); ++j)
|
||||||
|
{
|
||||||
|
output->tex_coordinates[index][oi+j] = (*iter)->tex_coordinates[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
pcl::IndicesPtr concatenate(const std::vector<pcl::IndicesPtr> & indices)
|
pcl::IndicesPtr concatenate(const std::vector<pcl::IndicesPtr> & indices)
|
||||||
{
|
{
|
||||||
//compute total size
|
//compute total size
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ std::vector<pcl::Vertices> filterCloseVerticesFromMesh(
|
|||||||
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud,
|
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud,
|
||||||
const std::vector<pcl::Vertices> & polygons,
|
const std::vector<pcl::Vertices> & polygons,
|
||||||
float radius,
|
float radius,
|
||||||
float angle,
|
float angle, // FIXME angle not used
|
||||||
bool keepLatestInRadius)
|
bool keepLatestInRadius)
|
||||||
{
|
{
|
||||||
UDEBUG("size=%d polygons=%d radius=%f angle=%f keepLatest=%d",
|
UDEBUG("size=%d polygons=%d radius=%f angle=%f keepLatest=%d",
|
||||||
@@ -428,21 +428,14 @@ pcl::TextureMesh::Ptr createTextureMesh(
|
|||||||
const std::map<int, cv::Mat> & images,
|
const std::map<int, cv::Mat> & images,
|
||||||
const std::string & tmpDirectory)
|
const std::string & tmpDirectory)
|
||||||
{
|
{
|
||||||
|
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh);
|
||||||
|
textureMesh->cloud = mesh->cloud;
|
||||||
|
textureMesh->tex_polygons.push_back(mesh->polygons);
|
||||||
|
|
||||||
// Original from pcl/gpu/kinfu_large_scale/tools/standalone_texture_mapping.cpp:
|
// Original from pcl/gpu/kinfu_large_scale/tools/standalone_texture_mapping.cpp:
|
||||||
// Author: Raphael Favier, Technical University Eindhoven, (r.mysurname <aT> tue.nl)
|
// Author: Raphael Favier, Technical University Eindhoven, (r.mysurname <aT> tue.nl)
|
||||||
|
|
||||||
// Create the texturemesh object that will contain our UV-mapped mesh
|
// Create the texturemesh object that will contain our UV-mapped mesh
|
||||||
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh);
|
|
||||||
textureMesh->cloud = mesh->cloud;
|
|
||||||
std::vector< pcl::Vertices> polygons;
|
|
||||||
|
|
||||||
// push faces into the texturemesh object
|
|
||||||
polygons.resize (mesh->polygons.size ());
|
|
||||||
for(size_t i =0; i < mesh->polygons.size (); ++i)
|
|
||||||
{
|
|
||||||
polygons[i] = mesh->polygons[i];
|
|
||||||
}
|
|
||||||
textureMesh->tex_polygons.push_back(polygons);
|
|
||||||
|
|
||||||
// create cameras
|
// create cameras
|
||||||
pcl::texture_mapping::CameraVector cameras = createTextureCameras(
|
pcl::texture_mapping::CameraVector cameras = createTextureCameras(
|
||||||
@@ -498,7 +491,7 @@ pcl::TextureMesh::Ptr createTextureMesh(
|
|||||||
textureMesh->tex_materials[i] = mesh_material;
|
textureMesh->tex_materials[i] = mesh_material;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort faces
|
// Texture by projection
|
||||||
pcl::TextureMapping<pcl::PointXYZ> tm; // TextureMapping object that will perform the sort
|
pcl::TextureMapping<pcl::PointXYZ> tm; // TextureMapping object that will perform the sort
|
||||||
tm.textureMeshwithMultipleCameras(*textureMesh, cameras);
|
tm.textureMeshwithMultipleCameras(*textureMesh, cameras);
|
||||||
|
|
||||||
|
|||||||
@@ -671,6 +671,9 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//used for organized texturing below
|
||||||
|
std::map<int, std::pair<std::map<int, int>, std::pair<int, int> > > organizedIndices;
|
||||||
|
|
||||||
//mesh
|
//mesh
|
||||||
UDEBUG("Meshing=%d", _ui->groupBox_meshing->isChecked()?1:0);
|
UDEBUG("Meshing=%d", _ui->groupBox_meshing->isChecked()?1:0);
|
||||||
if(_ui->groupBox_meshing->isChecked())
|
if(_ui->groupBox_meshing->isChecked())
|
||||||
@@ -700,9 +703,35 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
|
|
||||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr denseCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
|
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr denseCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
|
||||||
std::vector<pcl::Vertices> densePolygons;
|
std::vector<pcl::Vertices> densePolygons;
|
||||||
util3d::filterNotUsedVerticesFromMesh(*iter->second, polygons, *denseCloud, densePolygons);
|
std::map<int, int> newToOldIndices = util3d::filterNotUsedVerticesFromMesh(*iter->second, polygons, *denseCloud, densePolygons);
|
||||||
|
|
||||||
if(_ui->checkBox_assemble->isChecked())
|
if(!_ui->checkBox_assemble->isChecked() ||
|
||||||
|
(_ui->checkBox_textureMapping->isEnabled() &&
|
||||||
|
_ui->checkBox_textureMapping->isChecked() &&
|
||||||
|
_ui->doubleSpinBox_voxelSize_assembled->value() == 0.0)) // don't assemble now if we are texturing
|
||||||
|
{
|
||||||
|
if(_ui->checkBox_assemble->isChecked())
|
||||||
|
{
|
||||||
|
denseCloud = util3d::transformPointCloud(denseCloud, poses.at(iter->first));
|
||||||
|
}
|
||||||
|
|
||||||
|
pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh);
|
||||||
|
pcl::toPCLPointCloud2(*denseCloud, mesh->cloud);
|
||||||
|
mesh->polygons = densePolygons;
|
||||||
|
if(_ui->doubleSpinBox_meshDecimationFactor->isEnabled() &&
|
||||||
|
_ui->doubleSpinBox_meshDecimationFactor->value() > 0.0)
|
||||||
|
{
|
||||||
|
int count = mesh->polygons.size();
|
||||||
|
mesh = util3d::meshDecimation(mesh, (float)_ui->doubleSpinBox_meshDecimationFactor->value());
|
||||||
|
_progressDialog->appendText(tr("Mesh decimation (factor=%1) from %2 to %3 polygons").arg(_ui->doubleSpinBox_meshDecimationFactor->value()).arg(count).arg(mesh->polygons.size()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
organizedIndices.insert(std::make_pair(iter->first, std::make_pair(newToOldIndices, std::make_pair(iter->second->width, iter->second->height))));
|
||||||
|
}
|
||||||
|
meshes.insert(std::make_pair(iter->first, mesh));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
denseCloud = util3d::transformPointCloud(denseCloud, poses.at(iter->first));
|
denseCloud = util3d::transformPointCloud(denseCloud, poses.at(iter->first));
|
||||||
if(mergedClouds->size() == 0)
|
if(mergedClouds->size() == 0)
|
||||||
@@ -715,46 +744,6 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
util3d::appendMesh(*mergedClouds, mergedPolygons, *denseCloud, densePolygons);
|
util3d::appendMesh(*mergedClouds, mergedPolygons, *denseCloud, densePolygons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if(_ui->doubleSpinBox_voxelSize_assembled->value() == 0.0)
|
|
||||||
{
|
|
||||||
pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh);
|
|
||||||
pcl::toPCLPointCloud2(*denseCloud, mesh->cloud);
|
|
||||||
mesh->polygons = densePolygons;
|
|
||||||
if(_ui->doubleSpinBox_meshDecimationFactor->isEnabled() &&
|
|
||||||
_ui->doubleSpinBox_meshDecimationFactor->value() > 0.0)
|
|
||||||
{
|
|
||||||
int count = mesh->polygons.size();
|
|
||||||
mesh = util3d::meshDecimation(mesh, (float)_ui->doubleSpinBox_meshDecimationFactor->value());
|
|
||||||
_progressDialog->appendText(tr("Assembled mesh decimation (factor=%1) from %2 to %3 polygons").arg(_ui->doubleSpinBox_meshDecimationFactor->value()).arg(count).arg(mesh->polygons.size()));
|
|
||||||
}
|
|
||||||
meshes.insert(std::make_pair(iter->first, mesh));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
densePolygons = util3d::filterCloseVerticesFromMesh(
|
|
||||||
denseCloud,
|
|
||||||
densePolygons,
|
|
||||||
_ui->doubleSpinBox_voxelSize_assembled->value(),
|
|
||||||
M_PI/4,
|
|
||||||
true);
|
|
||||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr filteredCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
|
|
||||||
std::vector<pcl::Vertices> filteredPolygons;
|
|
||||||
util3d::filterNotUsedVerticesFromMesh(*denseCloud, densePolygons, *filteredCloud, filteredPolygons);
|
|
||||||
pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh);
|
|
||||||
pcl::toPCLPointCloud2(*filteredCloud, mesh->cloud);
|
|
||||||
mesh->polygons = filteredPolygons;
|
|
||||||
if(_ui->doubleSpinBox_meshDecimationFactor->isEnabled() &&
|
|
||||||
_ui->doubleSpinBox_meshDecimationFactor->value() > 0.0)
|
|
||||||
{
|
|
||||||
int count = mesh->polygons.size();
|
|
||||||
mesh = util3d::meshDecimation(mesh, (float)_ui->doubleSpinBox_meshDecimationFactor->value());
|
|
||||||
_progressDialog->appendText(tr("Assembled mesh decimation (factor=%1) from %2 to %3 polygons").arg(_ui->doubleSpinBox_meshDecimationFactor->value()).arg(count).arg(mesh->polygons.size()));
|
|
||||||
}
|
|
||||||
meshes.insert(std::make_pair(iter->first, mesh));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -769,7 +758,7 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
{
|
{
|
||||||
if(_ui->doubleSpinBox_voxelSize_assembled->value())
|
if(_ui->doubleSpinBox_voxelSize_assembled->value())
|
||||||
{
|
{
|
||||||
_progressDialog->appendText(tr("Filtering assembled mesh (points=%1, polygons=%2)...").arg(mergedClouds->size()).arg(mergedPolygons.size()));
|
_progressDialog->appendText(tr("Filtering assembled mesh for close vertices (points=%1, polygons=%2)...").arg(mergedClouds->size()).arg(mergedPolygons.size()));
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
|
|
||||||
mergedPolygons = util3d::filterCloseVerticesFromMesh(
|
mergedPolygons = util3d::filterCloseVerticesFromMesh(
|
||||||
@@ -865,7 +854,7 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UASSERT(uContains(poses, iter->first));
|
UASSERT(uContains(poses, iter->first));
|
||||||
cameras.insert(std::make_pair(iter->first, Transform::getIdentity()));
|
cameras.insert(std::make_pair(iter->first, _ui->checkBox_assemble->isChecked()?poses.at(iter->first):Transform::getIdentity()));
|
||||||
}
|
}
|
||||||
std::map<int, Transform> cameraPoses;
|
std::map<int, Transform> cameraPoses;
|
||||||
std::map<int, CameraModel> cameraModels;
|
std::map<int, CameraModel> cameraModels;
|
||||||
@@ -899,12 +888,67 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
}
|
}
|
||||||
if(cameraPoses.size())
|
if(cameraPoses.size())
|
||||||
{
|
{
|
||||||
pcl::TextureMesh::Ptr textureMesh = util3d::createTextureMesh(
|
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh);
|
||||||
iter->second,
|
std::map<int, std::pair<std::map<int, int>, std::pair<int, int> > >::iterator oter = organizedIndices.find(iter->first);
|
||||||
cameraPoses,
|
if(iter->first != 0 && oter != organizedIndices.end())
|
||||||
cameraModels,
|
{
|
||||||
images,
|
UDEBUG("Texture by pixels");
|
||||||
dir.filePath("tmp_textures").toStdString());
|
textureMesh->cloud = iter->second->cloud;
|
||||||
|
textureMesh->tex_polygons.push_back(iter->second->polygons);
|
||||||
|
int w = oter->second.second.first;
|
||||||
|
int h = oter->second.second.second;
|
||||||
|
UASSERT(w > 1 && h > 1);
|
||||||
|
UASSERT(textureMesh->tex_polygons.size() && textureMesh->tex_polygons[0].size());
|
||||||
|
textureMesh->tex_coordinates.resize(1);
|
||||||
|
int polygonSize = textureMesh->tex_polygons[0][0].vertices.size();
|
||||||
|
textureMesh->tex_coordinates[0].resize(polygonSize*textureMesh->tex_polygons[0].size());
|
||||||
|
for(unsigned int i=0; i<textureMesh->tex_polygons[0].size(); ++i)
|
||||||
|
{
|
||||||
|
const pcl::Vertices & vertices = textureMesh->tex_polygons[0][i];
|
||||||
|
UASSERT(polygonSize == vertices.vertices.size());
|
||||||
|
for(int k=0; k<polygonSize; ++k)
|
||||||
|
{
|
||||||
|
//uv
|
||||||
|
std::map<int, int>::iterator vter = oter->second.first.find(vertices.vertices[k]);
|
||||||
|
UASSERT(vter != oter->second.first.end());
|
||||||
|
int originalVertex = vter->second;
|
||||||
|
textureMesh->tex_coordinates[0][i*polygonSize+k] = Eigen::Vector2f(
|
||||||
|
float(originalVertex % w) / float(w), // u
|
||||||
|
float(h - originalVertex / w) / float(h)); // v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pcl::TexMaterial mesh_material;
|
||||||
|
mesh_material.tex_d = 1.0f;
|
||||||
|
mesh_material.tex_Ns = 75.0f;
|
||||||
|
mesh_material.tex_illum = 1;
|
||||||
|
|
||||||
|
std::stringstream tex_name;
|
||||||
|
tex_name << "material_" << iter->first;
|
||||||
|
tex_name >> mesh_material.tex_name;
|
||||||
|
|
||||||
|
std::string tmpDirectory = dir.filePath("tmp_textures").toStdString();
|
||||||
|
mesh_material.tex_file = uFormat("%s/%s%d.png", tmpDirectory.c_str(), "texture_", iter->first);
|
||||||
|
if(!cv::imwrite(mesh_material.tex_file, images.at(iter->first)))
|
||||||
|
{
|
||||||
|
UERROR("Cannot save texture of image %d", iter->first);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UINFO("Saved temporary texture: \"%s\"", mesh_material.tex_file.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
textureMesh->tex_materials.push_back(mesh_material);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UDEBUG("Texture by projection");
|
||||||
|
textureMesh = util3d::createTextureMesh(
|
||||||
|
iter->second,
|
||||||
|
cameraPoses,
|
||||||
|
cameraModels,
|
||||||
|
images,
|
||||||
|
dir.filePath("tmp_textures").toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
textureMeshes.insert(std::make_pair(iter->first, textureMesh));
|
textureMeshes.insert(std::make_pair(iter->first, textureMesh));
|
||||||
}
|
}
|
||||||
@@ -918,6 +962,18 @@ bool ExportCloudsDialog::getExportedClouds(
|
|||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(textureMeshes.size() > 1 && _ui->checkBox_assemble->isChecked())
|
||||||
|
{
|
||||||
|
_progressDialog->appendText(tr("Assembling %1 meshes...").arg(textureMeshes.size()));
|
||||||
|
QApplication::processEvents();
|
||||||
|
uSleep(100);
|
||||||
|
QApplication::processEvents();
|
||||||
|
|
||||||
|
pcl::TextureMesh::Ptr assembledMesh = util3d::concatenateTextureMeshes(uValuesList(textureMeshes));
|
||||||
|
textureMeshes.clear();
|
||||||
|
textureMeshes.insert(std::make_pair(0, assembledMesh));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1202,6 +1258,9 @@ void ExportCloudsDialog::saveMeshes(
|
|||||||
if(meshes.begin()->second->polygons.size())
|
if(meshes.begin()->second->polygons.size())
|
||||||
{
|
{
|
||||||
_progressDialog->appendText(tr("Saving the mesh (%1 polygons)...").arg(meshes.begin()->second->polygons.size()));
|
_progressDialog->appendText(tr("Saving the mesh (%1 polygons)...").arg(meshes.begin()->second->polygons.size()));
|
||||||
|
QApplication::processEvents();
|
||||||
|
uSleep(100);
|
||||||
|
QApplication::processEvents();
|
||||||
|
|
||||||
bool success =false;
|
bool success =false;
|
||||||
if(QFileInfo(path).suffix() == "")
|
if(QFileInfo(path).suffix() == "")
|
||||||
@@ -1350,6 +1409,9 @@ void ExportCloudsDialog::saveTextureMeshes(
|
|||||||
if(meshes.begin()->second->tex_materials.size())
|
if(meshes.begin()->second->tex_materials.size())
|
||||||
{
|
{
|
||||||
_progressDialog->appendText(tr("Saving the mesh (with %1 textures)...").arg(meshes.begin()->second->tex_materials.size()));
|
_progressDialog->appendText(tr("Saving the mesh (with %1 textures)...").arg(meshes.begin()->second->tex_materials.size()));
|
||||||
|
QApplication::processEvents();
|
||||||
|
uSleep(100);
|
||||||
|
QApplication::processEvents();
|
||||||
|
|
||||||
bool success =false;
|
bool success =false;
|
||||||
if(QFileInfo(path).suffix() == "")
|
if(QFileInfo(path).suffix() == "")
|
||||||
@@ -1424,7 +1486,8 @@ void ExportCloudsDialog::saveTextureMeshes(
|
|||||||
QString fullPath = path+QDir::separator()+currentPrefix+QDir::separator()+info.fileName();
|
QString fullPath = path+QDir::separator()+currentPrefix+QDir::separator()+info.fileName();
|
||||||
// relative path
|
// relative path
|
||||||
mesh.tex_materials[i].tex_file=(currentPrefix+QDir::separator()+info.fileName()).toStdString();
|
mesh.tex_materials[i].tex_file=(currentPrefix+QDir::separator()+info.fileName()).toStdString();
|
||||||
if(!QFile::copy(iter->second->tex_materials[i].tex_file.c_str(), fullPath))
|
if(!QFile::copy(iter->second->tex_materials[i].tex_file.c_str(), fullPath) &&
|
||||||
|
info.fileName().compare("occluded.png") != 0)
|
||||||
{
|
{
|
||||||
_progressDialog->appendText(tr("Failed copying texture \"%1\" to \"%2\".")
|
_progressDialog->appendText(tr("Failed copying texture \"%1\" to \"%2\".")
|
||||||
.arg(iter->second->tex_materials[i].tex_file.c_str()).arg(fullPath), Qt::darkRed);
|
.arg(iter->second->tex_materials[i].tex_file.c_str()).arg(fullPath), Qt::darkRed);
|
||||||
|
|||||||
@@ -4978,7 +4978,7 @@ void MainWindow::viewScans()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_exportScansDialog->viewScans(
|
_exportScansDialog->viewScans(
|
||||||
_currentPosesMap,
|
_ui->widget_mapVisibility->getVisiblePoses(),
|
||||||
_currentMapIds,
|
_currentMapIds,
|
||||||
_cachedSignatures,
|
_cachedSignatures,
|
||||||
_createdScans,
|
_createdScans,
|
||||||
@@ -4994,7 +4994,7 @@ void MainWindow::exportClouds()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_exportCloudsDialog->exportClouds(
|
_exportCloudsDialog->exportClouds(
|
||||||
_currentPosesMap,
|
_ui->widget_mapVisibility->getVisiblePoses(),
|
||||||
_currentMapIds,
|
_currentMapIds,
|
||||||
_cachedSignatures,
|
_cachedSignatures,
|
||||||
_createdClouds,
|
_createdClouds,
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ MapVisibilityWidget::MapVisibilityWidget(QWidget * parent) : QWidget(parent) {
|
|||||||
QVBoxLayout * layout2 = new QVBoxLayout(scrollAreaWidgetContent);
|
QVBoxLayout * layout2 = new QVBoxLayout(scrollAreaWidgetContent);
|
||||||
scrollAreaWidgetContent->setLayout(layout2);
|
scrollAreaWidgetContent->setLayout(layout2);
|
||||||
scrollArea->setWidget(scrollAreaWidgetContent);
|
scrollArea->setWidget(scrollAreaWidgetContent);
|
||||||
|
|
||||||
|
QCheckBox * selectAll = new QCheckBox("Select all", this);
|
||||||
|
connect(selectAll, SIGNAL(toggled(bool)), this, SLOT(selectAll(bool)));
|
||||||
|
verticalLayout1->addWidget(selectAll);
|
||||||
verticalLayout1->addWidget(scrollArea);
|
verticalLayout1->addWidget(scrollArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,4 +130,14 @@ void MapVisibilityWidget::signalVisibility()
|
|||||||
emit visibilityChanged(check->text().split('(').first().toInt(), check->isChecked());
|
emit visibilityChanged(check->text().split('(').first().toInt(), check->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapVisibilityWidget::selectAll(bool checked)
|
||||||
|
{
|
||||||
|
QWidget * area = this->findChild<QWidget*>("area");
|
||||||
|
QList<QCheckBox*> checkboxes = area->findChildren<QCheckBox*>();
|
||||||
|
for(int i = 0; i<checkboxes.size(); ++i)
|
||||||
|
{
|
||||||
|
checkboxes[i]->setChecked(checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace rtabmap */
|
} /* namespace rtabmap */
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ protected:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void signalVisibility();
|
void signalVisibility();
|
||||||
|
void selectAll(bool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateCheckBoxes();
|
void updateCheckBoxes();
|
||||||
|
|||||||
@@ -25,13 +25,13 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>773</width>
|
<width>773</width>
|
||||||
<height>1422</height>
|
<height>1394</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_8" columnstretch="0,1">
|
<layout class="QGridLayout" name="gridLayout_8" columnstretch="0,1">
|
||||||
<item row="1" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLabel" name="label_binaryFile_2">
|
<widget class="QLabel" name="label_binaryFile_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Assemble clouds/meshes to a single output cloud/mesh.</string>
|
<string>Assemble clouds/meshes to a single output cloud/mesh.</string>
|
||||||
@@ -41,24 +41,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="label_12">
|
|
||||||
<property name="text">
|
|
||||||
<string>Reconstruction flavor.</string>
|
|
||||||
</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.</string>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QSpinBox" name="spinBox_normalKSearch">
|
<widget class="QSpinBox" name="spinBox_normalKSearch">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
@@ -68,7 +51,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QLabel" name="label_binaryFile">
|
<widget class="QLabel" name="label_binaryFile">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Binary file.</string>
|
<string>Binary file.</string>
|
||||||
@@ -78,7 +61,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QCheckBox" name="checkBox_binary">
|
<widget class="QCheckBox" name="checkBox_binary">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
@@ -88,29 +71,15 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="2" 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="0">
|
|
||||||
<widget class="QCheckBox" name="checkBox_assemble">
|
<widget class="QCheckBox" name="checkBox_assemble">
|
||||||
<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_109">
|
<widget class="QLabel" name="label_voxel">
|
||||||
<property name="text">
|
<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>
|
<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>
|
||||||
</property>
|
</property>
|
||||||
@@ -119,7 +88,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize_assembled">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_voxelSize_assembled">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
<string> m</string>
|
<string> m</string>
|
||||||
@@ -138,6 +107,37 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" 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>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</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>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
Reference in New Issue
Block a user