iOS feb 2025 various updates (#1451)

* Using shadows on all texts and icons to see them better when background is white. Buffering database previews to show faster the Library. Updated how RAM usage is computed and now show max memory. Added warnings when RAM usage is low.

* Added measuring tool

* fixed map not shown when closing visualization

* Added measure text size setting, changed look and feel of point to point

* Fixed measuring point not showing

* Added fix for #1401

* Addressing #1407

* Export: Added colored OBJ options

* fixed index_t not existing on focal

* Fixed Settings not applied after restoring to all default settings witohut restarting the app (Marker detection not working issue #1455 )

* Marker detection: Fixing wrong depth used when rgb and depth image sizes cannot be divided exactly one from the the other #1455

* Added Marker Max Range option (default 1m)

* Added OBJ texture policy option (keep color on textureless polygons)

* Added texture/color blending option directly in the app. Added LAZ export option.

* Hiding measuring button if not mesh, dont zip if exporting to laz, updating Export XXX button based on the current context, fixed always blending texture/color on not visualization mode

* updated default marker max range to 2m

* bump ios app version

* fixing pcl 1.8.1 build

* fixed android build
This commit is contained in:
matlabbe
2025-03-15 10:58:03 -07:00
committed by GitHub
parent f329ebd42b
commit 28dbf1c98a
40 changed files with 3436 additions and 489 deletions

View File

@@ -350,6 +350,7 @@ public:
void setLighting(bool on);
void setShading(bool on);
void setEdgeVisibility(bool visible);
void setScalarVisibility(bool visible);
void setInteractorLayer(int layer);
bool isBackfaceCulling() const;
@@ -459,6 +460,7 @@ private:
QAction * _aSetLighting;
QAction * _aSetFlatShading;
QAction * _aSetEdgeVisibility;
QAction * _aSetScalarVisibility;
QAction * _aBackfaceCulling;
QAction * _aPolygonPicking;
QMenu * _menu;

View File

@@ -32,6 +32,7 @@ public:
protected:
virtual void OnMouseMove();
virtual void OnLeftButtonDown();
virtual void OnRightButtonDown();
protected:
friend class CloudViewer;

View File

@@ -80,6 +80,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vtkObjectFactory.h>
#include <vtkQuad.h>
#include <vtkWarpScalar.h>
#include <vtkUnsignedCharArray.h>
#include <opencv/vtkImageMatSource.h>
#if VTK_MAJOR_VERSION >= 7
@@ -96,6 +97,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/global_map/OctoMap.h>
#endif
// For compatibility with new VTK generic data arrays.
#ifdef vtkGenericDataArray_h
#define InsertNextTupleValue InsertNextTypedTuple
#endif
namespace rtabmap {
CloudViewer::CloudViewer(QWidget *parent, CloudViewerInteractorStyle * style) :
@@ -124,6 +130,7 @@ CloudViewer::CloudViewer(QWidget *parent, CloudViewerInteractorStyle * style) :
_aSetLighting(0),
_aSetFlatShading(0),
_aSetEdgeVisibility(0),
_aSetScalarVisibility(0),
_aBackfaceCulling(0),
_menu(0),
_trajectory(new pcl::PointCloud<pcl::PointXYZ>),
@@ -347,6 +354,9 @@ void CloudViewer::createMenu()
_aSetEdgeVisibility = new QAction("Show edges", this);
_aSetEdgeVisibility->setCheckable(true);
_aSetEdgeVisibility->setChecked(false);
_aSetScalarVisibility = new QAction("Show vertex colors", this);
_aSetScalarVisibility->setCheckable(true);
_aSetScalarVisibility->setChecked(true);
_aBackfaceCulling = new QAction("Backface culling", this);
_aBackfaceCulling->setCheckable(true);
_aBackfaceCulling->setChecked(true);
@@ -408,6 +418,7 @@ void CloudViewer::createMenu()
_menu->addAction(_aSetLighting);
_menu->addAction(_aSetFlatShading);
_menu->addAction(_aSetEdgeVisibility);
_menu->addAction(_aSetScalarVisibility);
_menu->addAction(_aBackfaceCulling);
_menu->addAction(_aPolygonPicking);
}
@@ -1408,10 +1419,20 @@ bool CloudViewer::addTextureMesh (
// Create points from mesh.cloud
vtkSmartPointer<vtkPoints> poly_points = vtkSmartPointer<vtkPoints>::New ();
vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New ();
bool has_color = false;
colors->SetNumberOfComponents(3);
colors->SetName ("Colors");
bool hasColors = false;
for(unsigned int i=0; i<mesh.cloud.fields.size(); ++i)
{
if(mesh.cloud.fields[i].name.compare("rgb") == 0)
{
hasColors = true;
break;
}
}
vtkSmartPointer<vtkMatrix4x4> transformation = vtkSmartPointer<vtkMatrix4x4>::New ();
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ> ());
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB> ());
pcl::fromPCLPointCloud2 (mesh.cloud, *cloud);
// no points --> exit
if (cloud->points.size () == 0)
@@ -1423,8 +1444,17 @@ bool CloudViewer::addTextureMesh (
poly_points->SetNumberOfPoints (cloud->points.size ());
for (std::size_t i = 0; i < cloud->points.size (); ++i)
{
const pcl::PointXYZ &p = cloud->points[i];
const pcl::PointXYZRGB &p = cloud->points[i];
poly_points->InsertPoint (i, p.x, p.y, p.z);
if(hasColors) {
unsigned char color[3] = {p.r, p.g, p.b};
#if VTK_MAJOR_VERSION > 7 || (VTK_MAJOR_VERSION==7 && VTK_MINOR_VERSION >= 1)
colors->InsertNextTypedTuple(color);
#else
colors->InsertNextTupleValue(color);
#endif
}
}
//create polys from polyMesh.tex_polygons
@@ -1443,8 +1473,9 @@ bool CloudViewer::addTextureMesh (
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata->SetPolys (polys);
polydata->SetPoints (poly_points);
if (has_color)
if (hasColors) {
polydata->GetPointData()->SetScalars(colors);
}
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New ();
#if VTK_MAJOR_VERSION < 6
@@ -1524,6 +1555,7 @@ bool CloudViewer::addTextureMesh (
actor->GetProperty()->SetEdgeVisibility(_aSetEdgeVisibility->isChecked());
actor->GetProperty()->SetBackfaceCulling(_aBackfaceCulling->isChecked());
actor->GetProperty()->SetFrontfaceCulling(_frontfaceCulling);
actor->GetMapper()->SetScalarVisibility(_aSetScalarVisibility->isChecked());
return true;
}
@@ -2892,6 +2924,21 @@ void CloudViewer::setEdgeVisibility(bool visible)
this->refreshView();
}
void CloudViewer::setScalarVisibility(bool visible)
{
_aSetScalarVisibility->setChecked(visible);
pcl::visualization::ShapeActorMapPtr shapeActorMap = _visualizer->getShapeActorMap();
for(pcl::visualization::ShapeActorMap::iterator iter=shapeActorMap->begin(); iter!=shapeActorMap->end(); ++iter)
{
vtkActor* actor = vtkActor::SafeDownCast (iter->second);
if(actor && _addedClouds.contains(iter->first))
{
actor->GetMapper()->SetScalarVisibility(_aSetScalarVisibility->isChecked());
}
}
this->refreshView();
}
void CloudViewer::setInteractorLayer(int layer)
{
_visualizer->getRendererCollection()->InitTraversal ();
@@ -3983,6 +4030,10 @@ void CloudViewer::handleAction(QAction * a)
{
this->setEdgeVisibility(_aSetEdgeVisibility->isChecked());
}
else if(a == _aSetScalarVisibility)
{
this->setScalarVisibility(_aSetScalarVisibility->isChecked());
}
else if(a == _aBackfaceCulling)
{
this->setBackfaceCulling(_aBackfaceCulling->isChecked(), _frontfaceCulling);

View File

@@ -333,4 +333,9 @@ void CloudViewerInteractorStyle::OnLeftButtonDown()
PCLVisualizerInteractorStyle::OnLeftButtonDown();
}
void CloudViewerInteractorStyle::OnRightButtonDown()
{
// ignore
}
} /* namespace rtabmap */

View File

@@ -240,6 +240,8 @@ ExportCloudsDialog::ExportCloudsDialog(QWidget *parent) :
connect(_ui->doubleSpinBox_meshingTextureMaxAngle, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(_ui->spinBox_mesh_minTextureClusterSize, SIGNAL(valueChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->lineEdit_meshingTextureRoiRatios, SIGNAL(textChanged(const QString &)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_distanceToCamPolicy, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->comboBox_texturingColorPolicy, SIGNAL(currentIndexChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_cameraFilter, SIGNAL(stateChanged(int)), this, SIGNAL(configChanged()));
connect(_ui->checkBox_cameraFilter, SIGNAL(stateChanged(int)), this, SLOT(updateReconstructionFlavor()));
connect(_ui->doubleSpinBox_cameraFilterRadius, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
@@ -467,6 +469,7 @@ void ExportCloudsDialog::saveSettings(QSettings & settings, const QString & grou
settings.setValue("mesh_textureMinCluster", _ui->spinBox_mesh_minTextureClusterSize->value());
settings.setValue("mesh_textureRoiRatios", _ui->lineEdit_meshingTextureRoiRatios->text());
settings.setValue("mesh_textureDistanceToCamPolicy", _ui->checkBox_distanceToCamPolicy->isChecked());
settings.setValue("mesh_textureVertexColorPolicy", _ui->comboBox_texturingColorPolicy->currentIndex());
settings.setValue("mesh_textureCameraFiltering", _ui->checkBox_cameraFilter->isChecked());
settings.setValue("mesh_textureCameraFilteringRadius", _ui->doubleSpinBox_cameraFilterRadius->value());
settings.setValue("mesh_textureCameraFilteringAngle", _ui->doubleSpinBox_cameraFilterAngle->value());
@@ -651,6 +654,7 @@ void ExportCloudsDialog::loadSettings(QSettings & settings, const QString & grou
_ui->spinBox_mesh_minTextureClusterSize->setValue(settings.value("mesh_textureMinCluster", _ui->spinBox_mesh_minTextureClusterSize->value()).toDouble());
_ui->lineEdit_meshingTextureRoiRatios->setText(settings.value("mesh_textureRoiRatios", _ui->lineEdit_meshingTextureRoiRatios->text()).toString());
_ui->checkBox_distanceToCamPolicy->setChecked(settings.value("mesh_textureDistanceToCamPolicy", _ui->checkBox_distanceToCamPolicy->isChecked()).toBool());
_ui->comboBox_texturingColorPolicy->setCurrentIndex(settings.value("mesh_textureVertexColorPolicy", _ui->comboBox_texturingColorPolicy->currentIndex()).toInt());
_ui->checkBox_cameraFilter->setChecked(settings.value("mesh_textureCameraFiltering", _ui->checkBox_cameraFilter->isChecked()).toBool());
_ui->doubleSpinBox_cameraFilterRadius->setValue(settings.value("mesh_textureCameraFilteringRadius", _ui->doubleSpinBox_cameraFilterRadius->value()).toDouble());
_ui->doubleSpinBox_cameraFilterAngle->setValue(settings.value("mesh_textureCameraFilteringAngle", _ui->doubleSpinBox_cameraFilterAngle->value()).toDouble());
@@ -832,6 +836,7 @@ void ExportCloudsDialog::restoreDefaults()
_ui->spinBox_mesh_minTextureClusterSize->setValue(50);
_ui->lineEdit_meshingTextureRoiRatios->setText("0.0 0.0 0.0 0.0");
_ui->checkBox_distanceToCamPolicy->setChecked(false);
_ui->comboBox_texturingColorPolicy->setCurrentIndex(0);
_ui->checkBox_cameraFilter->setChecked(false);
_ui->doubleSpinBox_cameraFilterRadius->setValue(0);
_ui->doubleSpinBox_cameraFilterAngle->setValue(30);
@@ -1352,7 +1357,10 @@ void ExportCloudsDialog::viewClouds(
blendingDecimation,
_ui->spinBox_textureBrightnessContrastRatioLow->value(),
_ui->spinBox_textureBrightnessContrastRatioHigh->value(),
_ui->checkBox_exposureFusion->isEnabled() && _ui->checkBox_exposureFusion->isChecked());
_ui->checkBox_exposureFusion->isEnabled() && _ui->checkBox_exposureFusion->isChecked(),
0,
255,
_ui->comboBox_texturingColorPolicy->currentIndex() == 1);
if(globalTextures.rows == globalTextures.cols)
{
globalTexture = globalTextures;
@@ -1362,44 +1370,112 @@ void ExportCloudsDialog::viewClouds(
_progressDialog->appendText(tr("Viewing the mesh %1 (%2 polygons)...").arg(iter->first).arg(mesh->tex_polygons.size()?mesh->tex_polygons[0].size():0));
_progressDialog->incrementStep();
bool hasColors = false;
for(unsigned int i=0; i<mesh->cloud.fields.size(); ++i)
{
if(mesh->cloud.fields[i].name.compare("rgb") == 0)
{
hasColors = true;
}
}
// VTK issue:
// tex_coordinates should be linked to points, not
// polygon vertices. Points linked to multiple different TCoords (different textures) should
// be duplicated.
for (unsigned int t = 0; t < mesh->tex_coordinates.size(); ++t)
if(hasColors)
{
if(mesh->tex_polygons[t].size())
for (unsigned int t = 0; t < mesh->tex_coordinates.size(); ++t)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr originalCloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::fromPCLPointCloud2(mesh->cloud, *originalCloud);
// make a cloud with as many points than polygon vertices
unsigned int nPoints = mesh->tex_coordinates[t].size();
UASSERT(nPoints == mesh->tex_polygons[t].size()*mesh->tex_polygons[t][0].vertices.size()); // assuming polygon size is constant!
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(nPoints);
unsigned int oi = 0;
for (unsigned int i = 0; i < mesh->tex_polygons[t].size(); ++i)
if(mesh->tex_polygons[t].size())
{
pcl::Vertices & vertices = mesh->tex_polygons[t][i];
for(unsigned int j=0; j<vertices.vertices.size(); ++j)
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr originalCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
pcl::fromPCLPointCloud2(mesh->cloud, *originalCloud);
// make a cloud with as many points than polygon vertices
unsigned int nPoints = mesh->tex_coordinates[t].size();
UASSERT(nPoints == mesh->tex_polygons[t].size()*mesh->tex_polygons[t][0].vertices.size()); // assuming polygon size is constant!
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
cloud->resize(nPoints);
unsigned int oi = 0;
size_t texCoordIndex = 0;
for (unsigned int i = 0; i < mesh->tex_polygons[t].size(); ++i)
{
UASSERT(oi < cloud->size());
UASSERT_MSG((int)vertices.vertices[j] < (int)originalCloud->size(), uFormat("%d vs %d", vertices.vertices[j], (int)originalCloud->size()).c_str());
cloud->at(oi) = originalCloud->at(vertices.vertices[j]);
vertices.vertices[j] = oi; // new vertice index
++oi;
pcl::Vertices & vertices = mesh->tex_polygons[t][i];
bool hasTexture = true;
for(unsigned int j=0; j<vertices.vertices.size(); ++j)
{
if(mesh->tex_coordinates[t][texCoordIndex][0] == -1 || mesh->tex_coordinates[t][texCoordIndex][1] == -1)
{
hasTexture = false;
break;
}
}
for(unsigned int j=0; j<vertices.vertices.size(); ++j)
{
UASSERT(oi < cloud->size());
UASSERT_MSG((int)vertices.vertices[j] < (int)originalCloud->size(), uFormat("%d vs %d", vertices.vertices[j], (int)originalCloud->size()).c_str());
cloud->at(oi) = originalCloud->at(vertices.vertices[j]);
if(hasTexture && _ui->comboBox_texturingColorPolicy->currentIndex() == 1) {
cloud->at(oi).r = 255;
cloud->at(oi).g = 255;
cloud->at(oi).b = 255;
}
vertices.vertices[j] = oi; // new vertice index
++oi;
}
texCoordIndex+=vertices.vertices.size();
}
pcl::toPCLPointCloud2(*cloud, mesh->cloud);
}
else
{
UWARN("No polygons for texture %d of mesh %d?!", t, iter->first);
}
pcl::toPCLPointCloud2(*cloud, mesh->cloud);
}
else
}
else
{
for (unsigned int t = 0; t < mesh->tex_coordinates.size(); ++t)
{
UWARN("No polygons for texture %d of mesh %d?!", t, iter->first);
if(mesh->tex_polygons[t].size())
{
pcl::PointCloud<pcl::PointNormal>::Ptr originalCloud(new pcl::PointCloud<pcl::PointNormal>);
pcl::fromPCLPointCloud2(mesh->cloud, *originalCloud);
// make a cloud with as many points than polygon vertices
unsigned int nPoints = mesh->tex_coordinates[t].size();
UASSERT(nPoints == mesh->tex_polygons[t].size()*mesh->tex_polygons[t][0].vertices.size()); // assuming polygon size is constant!
pcl::PointCloud<pcl::PointNormal>::Ptr cloud(new pcl::PointCloud<pcl::PointNormal>);
cloud->resize(nPoints);
unsigned int oi = 0;
for (unsigned int i = 0; i < mesh->tex_polygons[t].size(); ++i)
{
pcl::Vertices & vertices = mesh->tex_polygons[t][i];
for(unsigned int j=0; j<vertices.vertices.size(); ++j)
{
UASSERT(oi < cloud->size());
UASSERT_MSG((int)vertices.vertices[j] < (int)originalCloud->size(), uFormat("%d vs %d", vertices.vertices[j], (int)originalCloud->size()).c_str());
cloud->at(oi) = originalCloud->at(vertices.vertices[j]);
vertices.vertices[j] = oi; // new vertice index
++oi;
}
}
pcl::toPCLPointCloud2(*cloud, mesh->cloud);
}
else
{
UWARN("No polygons for texture %d of mesh %d?!", t, iter->first);
}
}
}
@@ -2682,7 +2758,7 @@ bool ExportCloudsDialog::getExportedClouds(
_ui->spinBox_meshMaxPolygons->isEnabled()?_ui->spinBox_meshMaxPolygons->value():0,
iter->second,
(float)_ui->doubleSpinBox_transferColorRadius->value(),
!(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()),
!(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked() && _ui->comboBox_texturingColorPolicy->currentIndex()==0),
_ui->checkBox_cleanMesh->isChecked(),
_ui->spinBox_mesh_minClusterSize->value(),
&texturingState);
@@ -3068,7 +3144,7 @@ bool ExportCloudsDialog::getExportedClouds(
_ui->spinBox_meshMaxPolygons->isEnabled()?_ui->spinBox_meshMaxPolygons->value():0,
vertices,
(float)_ui->doubleSpinBox_transferColorRadius->value(),
!(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()),
!(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked() && _ui->comboBox_texturingColorPolicy->currentIndex()==0),
_ui->checkBox_cleanMesh->isChecked(),
_ui->spinBox_mesh_minClusterSize->value(),
&texturingState);
@@ -3140,7 +3216,7 @@ bool ExportCloudsDialog::getExportedClouds(
_ui->spinBox_meshMaxPolygons->isEnabled()?_ui->spinBox_meshMaxPolygons->value():0,
mergedClouds,
(float)_ui->doubleSpinBox_transferColorRadius->value(),
!(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked()),
!(_ui->checkBox_textureMapping->isEnabled() && _ui->checkBox_textureMapping->isChecked() && _ui->comboBox_texturingColorPolicy->currentIndex()==0),
_ui->checkBox_cleanMesh->isChecked(),
_ui->spinBox_mesh_minClusterSize->value(),
&texturingState);
@@ -4697,7 +4773,8 @@ void ExportCloudsDialog::saveTextureMeshes(
_ui->spinBox_textureBrightnessContrastRatioHigh->value(),
_ui->checkBox_exposureFusion->isEnabled() && _ui->checkBox_exposureFusion->isChecked(),
0,
0,
255,
_ui->comboBox_texturingColorPolicy->currentIndex() == 1,
&gains,
&blendingGains,
&contrastValues);
@@ -4939,7 +5016,10 @@ void ExportCloudsDialog::saveTextureMeshes(
blendingDecimation,
_ui->spinBox_textureBrightnessContrastRatioLow->value(),
_ui->spinBox_textureBrightnessContrastRatioHigh->value(),
_ui->checkBox_exposureFusion->isEnabled() && _ui->checkBox_exposureFusion->isChecked());
_ui->checkBox_exposureFusion->isEnabled() && _ui->checkBox_exposureFusion->isChecked(),
0,
255,
_ui->comboBox_texturingColorPolicy->currentIndex() == 1);
}
bool singleTexture = mesh->tex_materials.size() == 1;
if(!singleTexture)
@@ -5114,28 +5194,31 @@ void ExportCloudsDialog::saveTextureMeshes(
}
}
bool ExportCloudsDialog::saveOBJFile(const QString &path, pcl::TextureMesh::Ptr &mesh) const {
#if PCL_VERSION_COMPARE(>=, 1, 13, 0)
mesh->tex_coord_indices = std::vector<std::vector<pcl::Vertices>>();
auto nr_meshes = static_cast<unsigned>(mesh->tex_polygons.size());
unsigned f_idx = 0;
for (unsigned m = 0; m < nr_meshes; m++) {
std::vector<pcl::Vertices> ci = mesh->tex_polygons[m];
for(std::size_t i = 0; i < ci.size(); i++) {
for (std::size_t j = 0; j < ci[i].vertices.size(); j++) {
ci[i].vertices[j] = ci[i].vertices.size() * (i + f_idx) + j;
}
}
mesh->tex_coord_indices.push_back(ci);
f_idx += static_cast<unsigned>(mesh->tex_polygons[m].size());
}
#endif
return pcl::io::saveOBJFile(path.toStdString(), *mesh) == 0;
}
bool ExportCloudsDialog::saveOBJFile(const QString &path, pcl::TextureMesh::Ptr &mesh) const {
bool ExportCloudsDialog::saveOBJFile(const QString &path, pcl::PolygonMesh &mesh) const {
return pcl::io::saveOBJFile(path.toStdString(), mesh) == 0;
}
#if PCL_VERSION_COMPARE(>=, 1, 13, 0)
mesh->tex_coord_indices = std::vector<std::vector<pcl::Vertices>>();
auto nr_meshes = static_cast<unsigned>(mesh->tex_polygons.size());
unsigned f_idx = 0;
for (unsigned m = 0; m < nr_meshes; m++) {
std::vector<pcl::Vertices> ci = mesh->tex_polygons[m];
for(std::size_t i = 0; i < ci.size(); i++) {
for (std::size_t j = 0; j < ci[i].vertices.size(); j++) {
ci[i].vertices[j] = ci[i].vertices.size() * (i + f_idx) + j;
}
}
mesh->tex_coord_indices.push_back(ci);
f_idx += static_cast<unsigned>(mesh->tex_polygons[m].size());
}
#endif
return util3d::saveOBJFile(path.toStdString(), *mesh) == 0;
}
bool ExportCloudsDialog::saveOBJFile(const QString &path, pcl::PolygonMesh &mesh) const {
return util3d::saveOBJFile(path.toStdString(), mesh) == 0;
}
}

View File

@@ -23,9 +23,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-2995</y>
<y>-3199</y>
<width>885</width>
<height>6152</height>
<height>6183</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
@@ -2438,20 +2438,106 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
<layout class="QVBoxLayout" name="verticalLayout_16">
<item>
<layout class="QGridLayout" name="gridLayout_15" columnstretch="0,1">
<item row="13" column="0">
<widget class="QSpinBox" name="spinBox_textureBrightnessContrastRatioHigh">
<item row="11" column="0">
<widget class="QCheckBox" name="checkBox_blending">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_meshingTextureSize_3">
<property name="text">
<string>Camera filtering. Some criteria to select which cameras are used for texturing.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshingTextureMaxDistance">
<property name="suffix">
<string> %</string>
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<number>0</number>
<double>0.000000000000000</double>
</property>
<property name="maximum">
<number>49</number>
<double>99.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>3.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_meshingTextureFormat">
<property name="text">
<string>Texture format.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_meshingTextureSize_10">
<property name="text">
<string>Maximum angle between camera and face to apply texture (0 means disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QLabel" name="label_exposureFusion">
<property name="text">
<string>Exposure fusion. Only used when textures are merged and brightness/contrast balance ratios are used (merging original texture + 1 for each ratios).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_meshingTextureSize_5">
<property name="text">
<string>Brightness and contrast balance low ratio. Only used when textures are merged.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_meshingTextureSize_2">
<property name="text">
<string>Maximum distance from the camera for polygons to be textured by this camera (0 means infinite). Only used with dense reconstruction flavor.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_meshingTextureSize_11">
<property name="text">
<string>Distance to camera policy. The closest camera from a polygon is used to texture the polygon. If disabled, the camera for which the polygon projection is the closest of the image center is used to texture the polygon.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="label_meshingTextureSize_6">
<property name="text">
<string>Brightness and contrast balance high ratio. Only used when textures are merged.</string>
@@ -2461,7 +2547,17 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
</property>
</widget>
</item>
<item row="11" column="0">
<item row="2" column="0">
<widget class="QSpinBox" name="spinBox_mesh_maxTextures">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QComboBox" name="comboBox_blendingDecimation">
<item>
<property name="text">
@@ -2505,23 +2601,93 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
</item>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="checkBox_blending">
<item row="7" column="1">
<widget class="QLabel" name="label_meshingTextureSize_4">
<property name="text">
<string/>
<string>Minimum polygon cluster size for texturing. This removes textures applied on sparse polygons. Only used with dense reconstruction flavor.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QSpinBox" name="spinBox_textureBrightnessContrastRatioHigh">
<property name="suffix">
<string> %</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>49</number>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_exposureFusion_3">
<widget class="QLabel" name="label_exposureFusion_2">
<property name="text">
<string>Blending decimation. </string>
<string>Blending. Only used with dense reconstruction flavor and if clouds are assembled.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="label_multiband">
<property name="text">
<string>MultiBand texturing. Only available on export and RTAB-Map should be built with AliceVision support.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshingTextureMaxAngle">
<property name="suffix">
<string> deg</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>180.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshingTextureMaxDepthError">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>99.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_meshingTextureSize_7">
<property name="text">
@@ -2532,72 +2698,24 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_meshingTextureSize_8">
<item row="17" column="0">
<widget class="QCheckBox" name="checkBox_multiband">
<property name="text">
<string>Maximum output textures.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
<string/>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_exposureFusion_2">
<item row="16" column="0">
<widget class="QCheckBox" name="checkBox_exposureFusion">
<property name="text">
<string>Blending. Only used with dense reconstruction flavor and if clouds are assembled.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
<string/>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_meshingTextureSize_2">
<item row="1" column="1">
<widget class="QLabel" name="label_meshingTextureSize">
<property name="text">
<string>Maximum distance from the camera for polygons to be textured by this camera (0 means infinite). Only used with dense reconstruction flavor.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshingTextureMaxDistance">
<property name="suffix">
<string> m</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>1.000000000000000</double>
</property>
<property name="value">
<double>3.000000000000000</double>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_meshingTextureSize_5">
<property name="text">
<string>Brightness and contrast balance low ratio. Only used when textures are merged.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_meshingTextureFormat">
<property name="text">
<string>Texture format.</string>
<string>Output texture size. If not set or when clouds are not assembled, all textures are saved separately. Warning: values higher than 2048 may not be compatible with all GPUs.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -2618,6 +2736,16 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
</item>
</widget>
</item>
<item row="7" column="0">
<widget class="QSpinBox" name="spinBox_mesh_minTextureClusterSize">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="comboBox_meshingTextureSize">
<item>
@@ -2667,17 +2795,17 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
</item>
</widget>
</item>
<item row="15" column="0">
<widget class="QCheckBox" name="checkBox_exposureFusion">
<item row="8" column="0">
<widget class="QCheckBox" name="checkBox_distanceToCamPolicy">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_meshingTextureSize_4">
<item row="2" column="1">
<widget class="QLabel" name="label_meshingTextureSize_8">
<property name="text">
<string>Minimum polygon cluster size for texturing. This removes textures applied on sparse polygons. Only used with dense reconstruction flavor.</string>
<string>Maximum output textures.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -2687,76 +2815,16 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
<item row="3" column="0">
<widget class="QLineEdit" name="lineEdit_meshingTextureRoiRatios"/>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_meshingTextureSize">
<item row="12" column="1">
<widget class="QLabel" name="label_exposureFusion_3">
<property name="text">
<string>Output texture size. If not set or when clouds are not assembled, all textures are saved separately. Warning: values higher than 2048 may not be compatible with all GPUs.</string>
<string>Blending decimation. </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="checkBox_cameraFilter">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QSpinBox" name="spinBox_textureBrightnessContrastRatioLow">
<property name="suffix">
<string> %</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>49</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QSpinBox" name="spinBox_mesh_minTextureClusterSize">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_meshingTextureSize_3">
<property name="text">
<string>Camera filtering. Some criteria to select which cameras are used for texturing.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_exposureFusion">
<property name="text">
<string>Exposure fusion. Only used when textures are merged and brightness/contrast balance ratios are used (merging original texture + 1 for each ratios).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="spinBox_mesh_maxTextures">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_meshingTextureSize_9">
<property name="text">
@@ -2767,92 +2835,53 @@ By Node ID and Camera Index: NodeID*10+CameraIndex</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshingTextureMaxDepthError">
<item row="13" column="0">
<widget class="QSpinBox" name="spinBox_textureBrightnessContrastRatioLow">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
<string> %</string>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>99.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_meshingTextureSize_10">
<property name="text">
<string>Maximum angle between camera and face to apply texture (0 means disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_meshingTextureMaxAngle">
<property name="suffix">
<string> deg</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>180.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
<number>49</number>
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QLabel" name="label_multiband">
<item row="10" column="0">
<widget class="QCheckBox" name="checkBox_cameraFilter">
<property name="text">
<string>MultiBand texturing. Only available on export and RTAB-Map should be built with AliceVision support.</string>
<string/>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_texturingVertexColorPolicy">
<property name="text">
<string>Output vertex color policy.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QCheckBox" name="checkBox_multiband">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_meshingTextureSize_11">
<property name="text">
<string>Distance to camera policy. The closest camera from a polygon is used to texture the polygon. If disabled, the camera for which the polygon projection is the closest of the image center is used to texture the polygon.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="checkBox_distanceToCamPolicy">
<property name="text">
<string/>
</property>
<item row="9" column="0">
<widget class="QComboBox" name="comboBox_texturingColorPolicy">
<item>
<property name="text">
<string>Colorless (standard OBJ)</string>
</property>
</item>
<item>
<property name="text">
<string>Keep color on textureless polygons only</string>
</property>
</item>
<item>
<property name="text">
<string>Keep all color</string>
</property>
</item>
</widget>
</item>
</layout>