ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
GeneralFilters.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 "GeneralFilters.h"
9 
10 // LOCAL
11 #include <Utils/cc2sm.h>
12 #include <Utils/sm2cc.h>
13 
14 #include "PclUtils/PCLModules.h"
16 
17 // ECV_PLUGINS
18 #include <ecvMainAppInterface.h>
19 
20 // CV_DB_LIB
21 #include <ecvPointCloud.h>
22 #include <ecvPolyline.h>
23 
24 // QT
25 #include <QMainWindow>
26 
29  tr("General Filters"),
30  tr("General Filters"),
31  tr("General Filters for the selected entity"),
32  ":/toolbar/PclAlgorithms/icons/generalFilter.png")),
33  m_dialog(nullptr),
34  m_polyline(nullptr),
35  m_dimension(2),
36  m_keepColors(true),
37  m_hasColors(false),
38  m_extractRemainings(false),
39  m_filterType(FilterType::CR_FILTER),
40  m_maxWindowSize(20),
41  m_slope(1.0f),
42  m_initialDistance(0.5f),
43  m_maxDistance(3.0f),
44  m_comparisonField("curvature"),
45  m_comparisonTypes("GT"),
46  m_minMagnitude(0.3f),
47  m_maxMagnitude(1.3f),
48  m_leafSize(0.01f) {}
49 
51  // we must delete parent-less dialogs ourselves!
52  if (m_dialog && m_dialog->parent() == nullptr) delete m_dialog;
53 }
54 
56  if (!m_dialog) {
58  }
60 
61  return m_dialog->exec() ? 1 : 0;
62 }
63 
65  assert(m_dialog);
66  if (!m_dialog) return;
67 
68  // fill in parameters from dialog
69  m_keepColors = m_dialog->keepColorCheckBox->isChecked();
70  switch (m_dialog->tab->currentIndex()) {
71  // Cloud Pass Through Filter
72  case 0: {
75  m_filterType = FilterType::PASS_FILTER;
76  break;
77  }
78  // Cloud Condition Removal Filter
79  case 1: {
83  m_filterType = FilterType::CR_FILTER;
84  break;
85  }
86  // Voxel Grid Filter
87  case 2: {
88  // m_sampleAllData =
89  // m_dialog->downsampleAllDataCheckBox->isChecked();
90  m_leafSize = static_cast<float>(m_dialog->leafSizeSpinBox->value());
91  m_filterType = FilterType::VOXEL_FILTER;
92  break;
93  }
94  // Progressive Morphological Filter
95  case 3: {
96  bool m_extractRemainings =
97  m_dialog->extractRemainingCheckBox->isChecked();
98  int m_maxWindowSize = m_dialog->maxWindowSizeSpinBox->value();
99  float m_slope = static_cast<float>(m_dialog->slopeSpinBox->value());
100  float m_initialDistance = static_cast<float>(
101  m_dialog->initialDistanceSpinBox->value());
102  float m_maxDistance =
103  static_cast<float>(m_dialog->maxDistanceSpinBox->value());
104  m_filterType = FilterType::PM_FILTER;
105  break;
106  }
107  // Crop Hull Filter
108  case 4: {
110  if (!m_polyline) {
112  }
113 
114  m_dimension = m_dialog->dimensionSpinBox->value();
115  m_filterType = FilterType::HULL_FILTER;
116  break;
117  }
118  default:
119  break;
120  }
121 }
122 
125  return -52;
126  }
127  return 1;
128 }
129 
131  // pointer to selected cloud
133  if (!cloud) return -1;
134 
135  // initialize all possible clouds
136  PCLCloud::Ptr out_cloud_sm(new PCLCloud);
137  PointCloudT::Ptr xyzCloud(new PointCloudT);
138  PointCloudRGB::Ptr rgbCloud(new PointCloudRGB);
139 
140  PCLCloud::Ptr sm_cloud = cc2smReader(cloud).getAsSM();
141  if (cloud->hasColors() || cloud->hasScalarFields()) {
142  FROM_PCL_CLOUD(*sm_cloud, *rgbCloud);
143  if (!rgbCloud) return -1;
144  m_hasColors = true;
145  } else {
146  FROM_PCL_CLOUD(*sm_cloud, *xyzCloud);
147  if (!xyzCloud) return -1;
148  m_hasColors = false;
149  }
150 
151  QString name = tr("%1-out").arg(cloud->getName());
152  switch (m_filterType) {
154  if (m_hasColors) {
155  PointCloudRGB::Ptr tempCloud(new PointCloudRGB);
156  if (!PCLModules::PassThroughFilter<PointRGB>(
157  rgbCloud, tempCloud, m_comparisonField,
159  return -1;
160  }
161  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
162  } else {
163  PointCloudT::Ptr tempCloud(new PointCloudT);
164  if (!PCLModules::PassThroughFilter<PointT>(
165  xyzCloud, tempCloud, m_comparisonField,
167  return -1;
168  }
169  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
170  }
171  name = tr("%1-passThrough").arg(cloud->getName());
172  break;
173  }
175  // init condition parameters
176  PCLModules::ConditionParameters param;
177  {
178  if (m_comparisonTypes.size() == 1) {
179  param.condition_type_ = PCLModules::ConditionParameters::
180  ConditionType::CONDITION_OR;
181  } else {
182  param.condition_type_ = PCLModules::ConditionParameters::
183  ConditionType::CONDITION_AND;
184  }
185  for (const QString& type : m_comparisonTypes) {
186  PCLModules::ConditionParameters::ComparisonParam comparison;
187  if (type == "GT") {
188  comparison.comparison_type_ = PCLModules::
189  ConditionParameters::ComparisonType::GT;
190  } else if (type == "GE") {
191  comparison.comparison_type_ = PCLModules::
192  ConditionParameters::ComparisonType::GE;
193  } else if (type == "LT") {
194  comparison.comparison_type_ = PCLModules::
195  ConditionParameters::ComparisonType::LT;
196  } else if (type == "LE") {
197  comparison.comparison_type_ = PCLModules::
198  ConditionParameters::ComparisonType::LE;
199  } else if (type == "EQ") {
200  comparison.comparison_type_ = PCLModules::
201  ConditionParameters::ComparisonType::EQ;
202  }
203  comparison.fieldName_ = m_comparisonField.toStdString();
204  comparison.min_threshold_ = m_minMagnitude;
205  comparison.max_threshold_ = m_maxMagnitude;
206  param.condition_params_.push_back(comparison);
207  }
208  }
209 
210  if (m_hasColors) {
211  PointCloudRGB::Ptr tempCloud(new PointCloudRGB);
212  if (!PCLModules::ConditionalRemovalFilter<PointRGB>(
213  rgbCloud, param, tempCloud, true)) {
214  return -1;
215  }
216  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
217  } else {
218  PointCloudT::Ptr tempCloud(new PointCloudT);
219  if (!PCLModules::ConditionalRemovalFilter<PointT>(
220  xyzCloud, param, tempCloud, true)) {
221  return -1;
222  }
223  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
224  }
225  name = tr("%1-condition").arg(cloud->getName());
226  break;
227  }
229  if (m_hasColors) {
230  PointCloudRGB::Ptr tempCloud(new PointCloudRGB);
231  if (!PCLModules::VoxelGridFilter<PointRGB>(
232  rgbCloud, tempCloud, m_leafSize, m_leafSize,
233  m_leafSize)) {
234  return -1;
235  }
236 
237  // if voxel grid failed and just return ignore this operation
238  if (tempCloud->size() == rgbCloud->size()) {
239  return 1;
240  }
241  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
242  } else {
243  PointCloudT::Ptr tempCloud(new PointCloudT);
244  if (!PCLModules::VoxelGridFilter<PointT>(xyzCloud, tempCloud,
246  m_leafSize)) {
247  return -1;
248  }
249  // if voxel grid failed and just return ignore this operation
250  if (tempCloud->size() == xyzCloud->size()) {
251  return 1;
252  }
253  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
254  }
255 
256  name = tr("%1-voxelGrid").arg(cloud->getName());
257  break;
258  }
260  if (m_hasColors) {
261  pcl::PointIndicesPtr ground(new pcl::PointIndices);
262  if (!PCLModules::ProgressiveMpFilter<PointRGB>(
263  rgbCloud, ground, m_maxWindowSize, m_slope,
265  ground->indices.size() == 0) {
266  return -1;
267  }
268 
269  PointCloudRGB::Ptr tempCloud(new PointCloudRGB);
270  if (m_extractRemainings) {
271  if (!PCLModules::ExtractIndicesFilter<PointRGB>(
272  rgbCloud, ground, nullptr, tempCloud)) {
273  return -1;
274  }
275  } else {
276  if (!PCLModules::ExtractIndicesFilter<PointRGB>(
277  rgbCloud, ground, tempCloud, nullptr)) {
278  return -1;
279  }
280  }
281 
282  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
283  } else {
284  pcl::PointIndicesPtr ground(new pcl::PointIndices);
285  if (!PCLModules::ProgressiveMpFilter<PointT>(
286  xyzCloud, ground, m_maxWindowSize, m_slope,
288  ground->indices.size() == 0) {
289  return -1;
290  }
291 
292  PointCloudT::Ptr tempCloud(new PointCloudT);
293  if (m_extractRemainings) {
294  if (!PCLModules::ExtractIndicesFilter<PointT>(
295  xyzCloud, ground, nullptr, tempCloud)) {
296  return -1;
297  }
298  } else {
299  if (!PCLModules::ExtractIndicesFilter<PointT>(
300  xyzCloud, ground, tempCloud, nullptr)) {
301  return -1;
302  }
303  }
304 
305  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
306  }
307  name = tr("%1-progressive").arg(cloud->getName());
308  break;
309  }
311  PointCloudT::Ptr boundary(new PointCloudT);
312  if (m_polyline && m_polyline->size() > 2) {
313  unsigned int pointNum = m_polyline->size();
314  boundary->resize(pointNum);
315  for (unsigned int i = 0; i < pointNum; ++i) {
316  const CCVector3* p = m_polyline->getPoint(i);
317  boundary->points[i].x = p->x;
318  boundary->points[i].y = p->y;
319  boundary->points[i].z = p->z;
320  }
321  } else {
322  size_t pointNum = m_boundary.size();
323  boundary->resize(pointNum);
324  for (size_t i = 0; i < pointNum; ++i) {
325  boundary->points[i].x = m_boundary[i].x;
326  boundary->points[i].y = m_boundary[i].y;
327  boundary->points[i].z = m_boundary[i].z;
328  }
329  }
330 
331  if (boundary->width * boundary->height == 0) {
332  return -1;
333  }
334 
335  if (m_hasColors) {
336  PointCloudRGB::Ptr tempCloud(new PointCloudRGB);
337  if (!PCLModules::CropHullFilter<PointRGB>(
338  rgbCloud, boundary, tempCloud, m_dimension)) {
339  return -1;
340  }
341  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
342  } else {
343  PointCloudT::Ptr tempCloud(new PointCloudT);
344  if (!PCLModules::CropHullFilter<PointT>(
345  xyzCloud, boundary, tempCloud, m_dimension)) {
346  return -1;
347  }
348  TO_PCL_CLOUD(*tempCloud, *out_cloud_sm);
349  }
350 
351  name = tr("%1-cropHull").arg(cloud->getName());
352  break;
353  }
354 
355  default:
356  break;
357  }
358 
359  if (out_cloud_sm->width * out_cloud_sm->height == 0) {
360  return -53;
361  }
362 
363  ccPointCloud* out_cloud_cc = pcl2cc::Convert(*out_cloud_sm);
364  {
365  if (!out_cloud_cc) {
366  // conversion failed (not enough memory?)
367  return -1;
368  }
369  out_cloud_cc->setName(name);
370  if (!m_keepColors) {
372  out_cloud_cc->setRGBColor(col);
373  out_cloud_cc->showColors(true);
374  out_cloud_cc->showSF(false);
375  }
376 
377  // copy global shift & scale
378  out_cloud_cc->setGlobalScale(cloud->getGlobalScale());
379  out_cloud_cc->setGlobalShift(cloud->getGlobalShift());
380  }
381 
382  cloud->setEnabled(false);
383  if (cloud->getParent()) cloud->getParent()->addChild(out_cloud_cc);
384 
385  emit newEntity(out_cloud_cc);
386 
387  return 1;
388 }
389 
390 QString GeneralFilters::getErrorMessage(int errorCode) {
391  switch (errorCode) {
392  // THESE CASES CAN BE USED TO OVERRIDE OR ADD FILTER-SPECIFIC ERRORS
393  // CODES ALSO IN DERIVED CLASSES DEFULAT MUST BE ""
394  case -51:
395  return tr(
396  "Selected entity does not have any suitable scalar field "
397  "or RGB. Intensity scalar field or RGB are needed for "
398  "computing SIFT");
399  case -52:
400  return tr(
401  "Wrong Parameters. One or more parameters cannot be "
402  "accepted");
403  case -53:
404  return tr(
405  "General Filter does not returned any point. Try relaxing "
406  "your parameters");
407  }
408 
409  return BasePclModule::getErrorMessage(errorCode);
410 }
std::string name
char type
Base abstract class for each implemented PCL filter.
Definition: BasePclModule.h:53
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)
void getContour(std::vector< CCVector3 > &contour)
ccPolyline * getPolyline()
const QString getComparisonField(float &minValue, float &maxValue)
QStringList m_comparisonTypes
bool m_extractRemainings
float m_initialDistance
FilterType m_filterType
virtual int openInputDialog()
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
std::vector< CCVector3 > m_boundary
virtual int checkParameters()
QString m_comparisonField
ccPolyline * m_polyline
virtual void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
virtual int compute()
Performs the actual filter job.
GeneralFiltersDlg * m_dialog
virtual ~GeneralFilters()
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
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.)
bool hasColors() const override
Returns whether colors are enabled or not.
bool setRGBColor(ColorCompType r, ColorCompType g, ColorCompType b)
Set a unique color for the whole cloud (shortcut)
bool hasScalarFields() const override
Returns whether one or more scalar fields are instantiated.
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.
unsigned size() const override
Returns the number of points.
const CCVector3 * getPoint(unsigned index) const override
Returns the ith point.
static Rgb Random(bool lightOnly=true)
Generates a random color.
RGB color structure.
Definition: ecvColorTypes.h:49
PCL filter description.
Definition: BasePclModule.h:26