ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
DONSegmentation.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 
8 #include "DONSegmentation.h"
9 
10 #include <Utils/cc2sm.h>
11 #include <Utils/sm2cc.h>
12 
13 #include "PclUtils/PCLModules.h"
14 #include "Tools/Common/ecvTools.h" // must below above three
16 
17 // CV_DB_LIB
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 #include <sstream>
29 
31  : BasePclModule(
32  PclModuleDescription(tr("DoN Segmentation"),
33  tr("DoN Segmentation"),
34  tr("DoN Segmentation from clouds"),
35  ":/toolbar/PclAlgorithms/icons/DoN.png")),
36  m_dialog(nullptr),
37  m_comparisonField("curvature"),
38  m_comparisonTypes("GT"),
39  m_smallScale(5.0f),
40  m_largeScale(10.0f),
41  m_minDonMagnitude(0.3f),
42  m_maxDonMagnitude(1.3f),
43  m_clusterTolerance(0.02f),
44  m_minClusterSize(100),
45  m_maxClusterSize(25000),
46  m_randomClusterColor(false) {}
47 
49  // we must delete parent-less dialogs ourselves!
50  if (m_dialog && m_dialog->parent() == nullptr) delete m_dialog;
51 }
52 
54  // do we have a selected cloud?
55  int have_cloud = isFirstSelectedCcPointCloud();
56  if (have_cloud != 1) return -11;
57 
58  return 1;
59 }
60 
62  // initialize the dialog object
63  if (!m_dialog)
65 
66  if (!m_dialog->exec()) return 0;
67 
68  return 1;
69 }
70 
72  if (!m_dialog) return;
73 
74  // get the parameters from the dialog
75  m_smallScale = static_cast<float>(m_dialog->smallScaleSpinBox->value());
76  m_largeScale = static_cast<float>(m_dialog->largeScaleSpinBox->value());
77 
79  static_cast<float>(m_dialog->minDonMagnitudeSpinBox->value());
81  static_cast<float>(m_dialog->maxDonMagnitudeSpinBox->value());
84 
85  m_randomClusterColor = m_dialog->randomClusterColorCheckBox->isChecked();
87  static_cast<float>(m_dialog->clusterToleranceSpinBox->value());
88  m_minClusterSize = m_dialog->minClusterSizeSpinBox->value();
89  m_maxClusterSize = m_dialog->maxClusterSizeSpinBox->value();
90 }
91 
95  m_comparisonTypes.size() == 0) {
96  return -52;
97  }
98  return 1;
99 }
100 
103  if (!cloud) return -1;
104 
105  // get xyz as pcl point cloud
106  PointCloudT::Ptr xyzCloud = cc2smReader(cloud).getXYZ2();
107  if (!xyzCloud) return -1;
108 
109  std::vector<int> dummy;
110  PCLModules::RemoveNaN<PointT>(xyzCloud, xyzCloud, dummy);
111 
112  // 1. update parameters
113  double cloudReolution =
114  PCLModules::ComputeCloudResolution<PointT>(xyzCloud);
115  {
116  m_smallScale *= cloudReolution;
117  m_largeScale *= cloudReolution;
118  m_clusterTolerance *= cloudReolution;
119  }
120 
121  // 2. compute small and large scale normals
122  PointCloudNormal::Ptr normals_small_scale(new PointCloudNormal);
123  PointCloudNormal::Ptr normals_large_scale(new PointCloudNormal);
124  {
125  if (!PCLModules::ComputeNormals<PointT, PointNT>(
126  xyzCloud, normals_small_scale, m_smallScale, false, true)) {
127  return -1;
128  }
129 
130  if (!PCLModules::ComputeNormals<PointT, PointNT>(
131  xyzCloud, normals_large_scale, m_largeScale, false, true)) {
132  return -1;
133  }
134  }
135 
136  // 3. Create output cloud for DoN results
137  PointCloudNormal::Ptr doncloud(new PointCloudNormal);
138  pcl::copyPointCloud<PointT, PointNT>(*xyzCloud, *doncloud);
139  if (!PCLModules::DONEstimation<PointT, PointNT, PointNT>(
140  xyzCloud, normals_small_scale, normals_large_scale, doncloud)) {
141  return -1;
142  }
143 
144  // 4. Filter by field magnitude
145  {
146  // init condition parameters
147  PCLModules::ConditionParameters param;
148  {
149  if (m_comparisonTypes.size() == 1) {
150  param.condition_type_ = PCLModules::ConditionParameters::
151  ConditionType::CONDITION_OR;
152  } else {
153  param.condition_type_ = PCLModules::ConditionParameters::
154  ConditionType::CONDITION_AND;
155  }
156  for (const QString& type : m_comparisonTypes) {
157  PCLModules::ConditionParameters::ComparisonParam comparison;
158  if (type == "GT") {
159  comparison.comparison_type_ =
160  PCLModules::ConditionParameters::ComparisonType::GT;
161  } else if (type == "GE") {
162  comparison.comparison_type_ =
163  PCLModules::ConditionParameters::ComparisonType::GE;
164  } else if (type == "LT") {
165  comparison.comparison_type_ =
166  PCLModules::ConditionParameters::ComparisonType::LT;
167  } else if (type == "LE") {
168  comparison.comparison_type_ =
169  PCLModules::ConditionParameters::ComparisonType::LE;
170  } else if (type == "EQ") {
171  comparison.comparison_type_ =
172  PCLModules::ConditionParameters::ComparisonType::EQ;
173  }
174  comparison.fieldName_ = m_comparisonField.toStdString();
175  comparison.min_threshold_ = m_minDonMagnitude;
176  comparison.max_threshold_ = m_maxDonMagnitude;
177  param.condition_params_.push_back(comparison);
178  }
179  }
180  PointCloudNormal::Ptr doncloud_filtered(new PointCloudNormal);
181  if (!PCLModules::ConditionalRemovalFilter<PointNT>(
182  doncloud, param, doncloud_filtered, false)) {
183  return -1;
184  }
185  doncloud = doncloud_filtered;
186  if (doncloud->width * doncloud->height == 0) {
187  return -1;
188  }
189  }
190 
191  // 5. cluster segmentation
192  std::vector<pcl::PointIndices> cluster_indices;
193  if (!PCLModules::EuclideanCluster<PointNT>(
194  doncloud, cluster_indices, m_clusterTolerance, m_minClusterSize,
195  m_maxClusterSize)) {
196  return -1;
197  }
198 
199  if (cluster_indices.size() == 0 || cluster_indices.size() > 300) {
200  return -53;
201  }
202 
203  // 6. processing result
204  std::vector<std::vector<size_t>> clusterIndices;
205  for (auto& cluster : cluster_indices) {
206  std::vector<size_t> cs;
207  cs.resize(cluster.indices.size());
208  for (size_t i = 0; i < cluster.indices.size(); ++i) {
209  cs[i] = (static_cast<size_t>(cluster.indices[i]));
210  }
211 
212  clusterIndices.push_back(cs);
213  }
214 
215  bool error = false;
216  ccHObject* group =
217  ecvTools::GetClousterGroup(cloud, clusterIndices, m_minClusterSize,
219 
220  if (group) {
221  group->setName(group->getName() +
222  tr("-Tolerance(%1)-ClusterSize(%2-%3)")
223  .arg(m_clusterTolerance)
224  .arg(m_minClusterSize)
225  .arg(m_maxClusterSize));
226 
227  unsigned count = group->getChildrenNumber();
228  m_app->dispToConsole(tr("[DONSegmentation] %1 cluster(s) where created "
229  "from cloud '%2'")
230  .arg(count)
231  .arg(cloud->getName()));
232 
233  if (error) {
234  m_app->dispToConsole(tr("Error(s) occurred during the generation "
235  "of clusters! Result may be incomplete"),
237  }
238 
239  cloud->setEnabled(false);
240  if (cloud->getParent()) cloud->getParent()->addChild(group);
241 
242  emit newEntity(group);
243 
244  } else if (error) {
245  return -54;
246  } else {
247  return -1;
248  }
249 
250  return 1;
251 }
252 
253 QString DONSegmentation::getErrorMessage(int errorCode) {
254  switch (errorCode) {
255  // THESE CASES CAN BE USED TO OVERRIDE OR ADD FILTER-SPECIFIC ERRORS
256  // CODES ALSO IN DERIVED CLASSES DEFULAT MUST BE ""
257  case -51:
258  return tr(
259  "Selected entity does not have any suitable scalar field "
260  "or RGB.");
261  case -52:
262  return tr(
263  "Wrong Parameters. One or more parameters cannot be "
264  "accepted");
265  case -53:
266  return tr(
267  "Difference of Normals Segmentation could not get any "
268  "cluster or "
269  "the clusters are more than 300 for the given dataset. Try "
270  "relaxing your parameters");
271  case -54:
272  return tr("An error occurred during the generation of clusters!");
273  }
274 
275  return BasePclModule::getErrorMessage(errorCode);
276 }
int count
char type
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.
void getComparisonTypes(QStringList &types)
const QString getComparisonField()
DONSegmentationDlg * m_dialog
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
virtual ~DONSegmentation()
virtual void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
virtual int compute()
Performs the actual filter job.
virtual int checkSelected()
Checks if current selection is compliant with the filter.
virtual int openInputDialog()
QString m_comparisonField
virtual int checkParameters()
QStringList m_comparisonTypes
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
unsigned getChildrenNumber() const
Returns the number of children.
Definition: ecvHObject.h:312
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
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
virtual QWidget * getActiveWindow()=0
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
static void error(char *msg)
Definition: lsd.c:159
PCL filter description.
Definition: BasePclModule.h:26