Merge branch 'ios_feb_2025_updates' of github.com:introlab/rtabmap into ios_feb_2025_updates

This commit is contained in:
matlabbe
2025-03-09 15:26:04 -07:00
10 changed files with 897 additions and 284 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>