ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
SACSegmentation.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 "SACSegmentation.h"
9 
10 #include <Utils/PCLCloud.h>
11 #include <Utils/cc2sm.h>
12 #include <Utils/sm2cc.h>
13 
14 #include "PclUtils/PCLModules.h"
15 #include "Tools/Common/ecvTools.h" // must below above three
17 
18 // CV_DB_LIB
19 #include <ecvPointCloud.h>
20 
21 // ECV_PLUGINS
22 #include <ecvMainAppInterface.h>
23 
24 // QT
25 #include <QMainWindow>
26 
27 // SYSTEM
28 #include <iostream>
29 #include <sstream>
30 
31 int extractRecursive(PointCloudT::Ptr xyzCloud,
32  PointCloudT::Ptr cloudRemained,
33  std::vector<PointCloudT::Ptr>& cloudExtractions,
34  int maxIterations,
35  float probability,
36  float minRadiusLimits,
37  float maxRadiusLimits,
38  float distanceThreshold,
39  int methodType,
40  int modelType,
41  float normalDisWeight,
42  float maxRemainingRatio,
43  bool exportExtraction,
44  bool recursive = false,
45  ecvMainAppInterface* app = nullptr);
46 
49  tr("SAC Segmentation"),
50  tr("SAC Segmentation"),
51  tr("SAC Segmentation from clouds"),
52  ":/toolbar/PclAlgorithms/icons/SAC_Segmentation.png")),
53  m_dialog(nullptr),
54  m_distanceThreshold(0.01f),
55  m_normalDisWeight(0.1f),
56  m_probability(0.95f),
57  m_minRadiusLimits(0.01f),
58  m_maxRadiusLimits(10.0f),
59  m_maxIterations(100),
60  m_methodType(0),
61  m_modelType(0),
62  m_exportExtraction(true),
63  m_exportRemaining(true),
64  m_maxRemainingRatio(0.3f),
65  m_recursiveMode(false),
66  m_useVoxelGrid(false),
67  m_leafSize(0.01f) {}
68 
70  // we must delete parent-less dialogs ourselves!
71  if (m_dialog && m_dialog->parent() == nullptr) delete m_dialog;
72 }
73 
75  // do we have a selected cloud?
76  int have_cloud = isFirstSelectedCcPointCloud();
77  if (have_cloud != 1) return -11;
78 
79  return 1;
80 }
81 
83  // initialize the dialog object
84  if (!m_dialog)
86 
87  if (!m_dialog->exec()) return 0;
88 
89  return 1;
90 }
91 
93  if (!m_dialog) return;
94 
95  // get the parameters from the dialog
96  m_modelType = m_dialog->modelTypeCombo->currentIndex();
97  m_methodType = m_dialog->methodTypeCombo->currentIndex();
98 
100  static_cast<float>(m_dialog->disThresholdSpinBox->value());
101  m_probability = static_cast<float>(m_dialog->probabilitySpinBox->value());
102  m_minRadiusLimits = static_cast<float>(m_dialog->minRadiusSpinBox->value());
103  m_maxRadiusLimits = static_cast<float>(m_dialog->maxRadiusSpinBox->value());
104  m_maxIterations = m_dialog->maxIterationspinBox->value();
106  static_cast<float>(m_dialog->normalDisWeightSpinBox->value());
107 
108  m_useVoxelGrid = m_dialog->useVoxelGridCheckBox->isChecked();
109  m_leafSize = static_cast<float>(m_dialog->leafSizeSpinBox->value());
110  m_recursiveMode = m_dialog->recursiveModeCheckBox->isChecked();
112  static_cast<float>(m_dialog->maxRemainingRatioSpinBox->value());
113  m_exportExtraction = m_dialog->exportExtractionCheckBox->isChecked();
114  m_exportRemaining = m_dialog->exportRemainingCheckBox->isChecked();
115 }
116 
119  return -52;
120  }
121 
123  return -51;
124  }
125 
126  return 1;
127 }
128 
131  if (!cloud) return -1;
132 
133  // get xyz as pcl point cloud
134  PointCloudT::Ptr cloudFiltered = cc2smReader(cloud).getXYZ2();
135  if (!cloudFiltered) return -1;
136 
137  // voxel grid filter
138  if (m_useVoxelGrid) {
139  PointCloudT::Ptr tempCloud(new PointCloudT);
140  if (!PCLModules::VoxelGridFilter<PointT>(cloudFiltered, tempCloud,
142  m_leafSize)) {
143  return -1;
144  }
145  cloudFiltered = tempCloud;
146  }
147 
148  PointCloudT::Ptr cloudRemained(new PointCloudT());
149  std::vector<PointCloudT::Ptr> cloudExtractions;
150 
151  if (!extractRecursive(cloudFiltered, cloudRemained, cloudExtractions,
156  return -53;
157  }
158 
159  bool error = false;
160  ccHObject* group = ecvTools::GetSegmentationGroup(
161  cloud, m_exportRemaining ? cloudRemained : nullptr,
162  cloudExtractions, true, error);
163 
164  if (group) {
165  if (m_recursiveMode) {
166  group->setName(
167  group->getName() +
168  tr("-MaxRemainingRatio[%1]").arg(m_maxRemainingRatio));
169  } else {
170  group->setName(group->getName() +
171  tr("-SingleSegmentation[Distance Threshold %1]")
172  .arg(m_distanceThreshold));
173  }
174 
175  unsigned count = group->getChildrenNumber();
176  m_app->dispToConsole(tr("[SACSegmentation::compute] %1 extracted "
177  "segment(s) where created from cloud '%2'")
178  .arg(cloudExtractions.size())
179  .arg(cloud->getName()));
180 
181  if (error) {
182  m_app->dispToConsole(tr("Error(s) occurred during the generation "
183  "of segments! Result may be incomplete"),
185  }
186 
187  cloud->setEnabled(false);
188  if (cloud->getParent()) cloud->getParent()->addChild(group);
189 
190  emit newEntity(group);
191 
192  } else if (error) {
193  return -54;
194  } else {
195  return -1;
196  }
197 
198  return 1;
199 }
200 
201 // DGM this function will modify the cloudFiltered
202 int extractRecursive(PointCloudT::Ptr cloudFilterd,
203  PointCloudT::Ptr cloudRemained,
204  std::vector<PointCloudT::Ptr>& cloudExtractions,
205  int maxIterations,
206  float probability,
207  float minRadiusLimits,
208  float maxRadiusLimits,
209  float distanceThreshold,
210  int methodType,
211  int modelType,
212  float normalDisWeight,
213  float maxRemainingRatio,
214  bool exportExtraction,
215  bool recursive,
216  ecvMainAppInterface* app) {
217  pcl::PointIndices::Ptr inliers(new pcl::PointIndices());
218  pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
219 
220  int i = 0, nr_points = (int)cloudFilterd->points.size();
221  while (cloudFilterd->points.size() > maxRemainingRatio * nr_points) {
222  // Segment the largest planar component from the remaining cloud
223  if (!PCLModules::GetSACSegmentation(
224  cloudFilterd, inliers, coefficients, methodType, modelType,
225  distanceThreshold, probability, maxIterations,
226  minRadiusLimits, maxRadiusLimits, normalDisWeight)) {
227  app->dispToConsole("PCLModules::GetSACSegmentation failed",
229  return -1;
230  }
231 
232  if (inliers->indices.size() == 0) {
233  break;
234  }
235 
236  // Extract the extractions and remainings from the input cloud
237  PointCloudT::Ptr cloudExtracted(new PointCloudT());
238  if (!PCLModules::ExtractIndicesFilter<PointT>(
239  cloudFilterd, inliers, cloudExtracted, cloudRemained)) {
240  app->dispToConsole("PCLModules::ExtractIndicesFilter failed",
242  return -1;
243  }
244 
245  if (exportExtraction) {
246  cloudExtractions.push_back(cloudExtracted);
247  }
248  *cloudFilterd = *cloudRemained;
249 
250  if (!recursive) break;
251  }
252  return 1;
253 }
254 
255 QString SACSegmentation::getErrorMessage(int errorCode) {
256  switch (errorCode) {
257  // THESE CASES CAN BE USED TO OVERRIDE OR ADD FILTER-SPECIFIC ERRORS
258  // CODES ALSO IN DERIVED CLASSES DEFULAT MUST BE ""
259 
260  case -51:
261  return tr(
262  "must select one of 'Export Extraction' and "
263  "'exportRemaining' or both");
264  case -52:
265  return tr(
266  "Wrong Parameters. One or more parameters cannot be "
267  "accepted");
268  case -53:
269  return tr(
270  "SAC Segmentation could not estimate a model for the given "
271  "dataset. Try relaxing your parameters");
272  case -54:
273  return tr("An error occurred during the generation of segments!");
274  }
275 
276  return BasePclModule::getErrorMessage(errorCode);
277 }
int count
int extractRecursive(PointCloudT::Ptr xyzCloud, PointCloudT::Ptr cloudRemained, std::vector< PointCloudT::Ptr > &cloudExtractions, int maxIterations, float probability, float minRadiusLimits, float maxRadiusLimits, float distanceThreshold, int methodType, int modelType, float normalDisWeight, float maxRemainingRatio, bool exportExtraction, bool recursive=false, ecvMainAppInterface *app=nullptr)
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.
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
virtual void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
virtual ~SACSegmentation()
virtual int checkSelected()
Checks if current selection is compliant with the filter.
virtual int openInputDialog()
virtual int compute()
Performs the actual filter job.
SACSegmentationDlg * m_dialog
virtual int checkParameters()
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.)
Main application interface (for plugins)
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