ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PoissonReconstruction.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <Utils/cc2sm.h>
11 #include <Utils/sm2cc.h>
12 
13 #include "PclUtils/PCLModules.h"
15 
16 // CV_DB_LIB
17 #include <ecvMesh.h>
18 #include <ecvPointCloud.h>
19 
20 // ECV_PLUGINS
21 #include <ecvMainAppInterface.h>
22 
23 // QT
24 #include <QMainWindow>
25 
26 // SYSTEM
27 #include <iostream>
28 
31  tr("Poisson Reconstruction"),
32  tr("Poisson Reconstruction"),
33  tr("Poisson Reconstruction from clouds"),
34  ":/toolbar/PclAlgorithms/icons/poisson.png")),
35  m_dialog(nullptr),
36  m_normalSearchRadius(10),
37  m_knn_radius(10),
38  m_useKnn(false),
39  m_degree(2),
40  m_treeDepth(8),
41  m_isoDivideDepth(8),
42  m_solverDivideDepth(8),
43  m_scale(1.25f),
44  m_samplesPerNode(3.0f),
45  m_useConfidence(true),
46  m_useManifold(true),
47  m_outputPolygons(false) {}
48 
50  // we must delete parent-less dialogs ourselves!
51  if (m_dialog && m_dialog->parent() == nullptr) delete m_dialog;
52 }
53 
55  // do we have a selected cloud?
56  int have_cloud = isFirstSelectedCcPointCloud();
57  if (have_cloud != 1) return -11;
58 
59  return 1;
60 }
61 
63  // initialize the dialog object
64  if (!m_dialog)
66  : 0);
67 
69  if (cloud) {
70  ccBBox bBox = cloud->getOwnBB();
71  if (bBox.isValid())
72  m_dialog->normalSearchRadius->setValue(bBox.getDiagNorm() * 0.005);
73  }
74 
75  if (!m_dialog->exec()) return 0;
76 
77  return 1;
78 }
79 
81  if (!m_dialog) return;
82 
83  // get the parameters from the dialog
84  m_useKnn = m_dialog->useKnnCheckBoxForTriangulation->isChecked();
85  m_knn_radius = m_dialog->knnSpinBoxForTriangulation->value();
87  static_cast<float>(m_dialog->normalSearchRadius->value());
88 
89  m_degree = m_dialog->degreeSpinbox->value();
90  m_treeDepth = m_dialog->treeDepthSpinbox->value();
91  m_isoDivideDepth = m_dialog->isoDivideSpinbox->value();
92  m_solverDivideDepth = m_dialog->solverDivideSpinbox->value();
93 
94  m_scale = static_cast<float>(m_dialog->scaleSpinbox->value());
96  static_cast<float>(m_dialog->samplesPerNodeSpinbox->value());
97 
98  m_useConfidence = m_dialog->confidenceCheckBox->isChecked();
99  m_useManifold = m_dialog->manifoldCheckBox->isChecked();
100  m_outputPolygons = m_dialog->outputPolygonsCheckBox->isChecked();
101 }
102 
104 
107  if (!cloud) return -1;
108 
109  // create storage for normals
110  pcl::PointCloud<pcl::PointNormal>::Ptr cloudWithNormals(
111  new pcl::PointCloud<pcl::PointNormal>);
112 
113  if (!cloud->hasNormals()) {
114  // get xyz as pcl point cloud
115  pcl::PointCloud<pcl::PointXYZ>::Ptr xyzCloud =
116  cc2smReader(cloud).getXYZ2();
117  if (!xyzCloud) return -1;
118 
119  // now compute
120  pcl::PointCloud<NormalT>::Ptr normals(new pcl::PointCloud<NormalT>);
121  int result = PCLModules::ComputeNormals<pcl::PointXYZ, NormalT>(
122  xyzCloud, normals,
124  if (result < 0) return -1;
125 
126  // concat points and normals
127  pcl::concatenateFields(*xyzCloud, *normals, *cloudWithNormals);
128  CVLog::Print(
129  tr("[PoissonReconstruction::compute] generate new normals"));
130  } else {
131  PCLCloud::Ptr sm_cloud = cc2smReader(cloud).getAsSM();
132  FROM_PCL_CLOUD(*sm_cloud, *cloudWithNormals);
133  CVLog::Print(
134  tr("[PoissonReconstruction::compute] find normals and use the "
135  "normals"));
136  }
137 
138  // reconstruction
139  PCLMesh mesh;
140 
141  // options
142  int result = PCLModules::GetPoissonReconstruction(
143  cloudWithNormals, mesh, m_degree, m_treeDepth, m_isoDivideDepth,
146  if (result < 0) return -1;
147 
148  PCLCloud out_cloud_sm(mesh.cloud);
149  if (out_cloud_sm.height * out_cloud_sm.width == 0) {
150  // cloud is empty
151  return -53;
152  }
153 
154  ccMesh* out_mesh = pcl2cc::Convert(out_cloud_sm, mesh.polygons);
155  if (!out_mesh) {
156  // conversion failed (not enough memory?)
157  return -1;
158  }
159 
160  unsigned vertCount = out_mesh->getAssociatedCloud()->size();
161  unsigned faceCount = out_mesh->size();
162  CVLog::Print(tr("[Poisson-Reconstruction] %1 points, %2 face(s)")
163  .arg(vertCount)
164  .arg(faceCount));
165 
166  out_mesh->setName(tr("Poisson Reconstruction"));
167  // copy global shift & scale
168  out_mesh->getAssociatedCloud()->setGlobalScale(cloud->getGlobalScale());
169  out_mesh->getAssociatedCloud()->setGlobalShift(cloud->getGlobalShift());
170 
171  if (cloud->getParent()) cloud->getParent()->addChild(out_mesh);
172 
173  emit newEntity(out_mesh);
174 
175  return 1;
176 }
177 
179  switch (errorCode) {
180  // THESE CASES CAN BE USED TO OVERRIDE OR ADD FILTER-SPECIFIC ERRORS
181  // CODES ALSO IN DERIVED CLASSES DEFULAT MUST BE ""
182 
183  case -51:
184  return tr(
185  "Selected entity does not have any suitable scalar field "
186  "or RGB.");
187  case -52:
188  return tr(
189  "Wrong Parameters. One or more parameters cannot be "
190  "accepted");
191  case -53:
192  return tr(
193  "Poisson Reconstruction does not returned any point. Try "
194  "relaxing your parameters");
195  default:
196  break;
197  }
198 
199  return BasePclModule::getErrorMessage(errorCode);
200 }
core::Tensor result
Definition: VtkUtils.cpp:76
Base abstract class for each implemented PCL filter.
Definition: BasePclModule.h:53
int isFirstSelectedCcPointCloud()
Returns 1 if the first selected object is a ccPointCloud.
void newEntity(ccHObject *)
Signal emitted when a new entity is created by the filter.
ecvMainAppInterface * m_app
Associated application interface.
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
ccPointCloud * getSelectedEntityAsCCPointCloud() const
Returns the first selected entity as a ccPointCloud.
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
virtual int compute()
Performs the actual filter job.
PoissonReconstructionDlg * m_dialog
virtual int checkSelected()
Checks if current selection is compliant with the filter.
virtual void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
Bounding box structure.
Definition: ecvBBox.h:25
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
Definition: ecvHObject.h:245
Triangular mesh.
Definition: ecvMesh.h:35
ccGenericPointCloud * getAssociatedCloud() const override
Returns the vertices cloud.
Definition: ecvMesh.h:143
virtual unsigned size() const override
Returns the number of triangles.
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool hasNormals() const override
Returns whether normals are enabled or not.
virtual void setGlobalScale(double scale)
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
T getDiagNorm() const
Returns diagonal length.
Definition: BoundingBox.h:172
bool isValid() const
Returns whether bounding box is valid or not.
Definition: BoundingBox.h:203
virtual unsigned size() const =0
Returns the number of points.
virtual QWidget * getActiveWindow()=0
double normals[3]
PCL filter description.
Definition: BasePclModule.h:26