ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvSubsamplingDlg.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 "ecvSubsamplingDlg.h"
9 
10 // CV_CORE_LIB
11 #include <CloudSamplingTools.h>
12 #include <DgmOctree.h>
14 #include <ReferenceCloud.h>
15 #include <ScalarField.h>
16 
17 // CV_DB_LIB
18 #include <CVLog.h>
19 #include <ecvGenericPointCloud.h>
20 #include <ecvOctree.h>
21 
22 // Exponent of the 'log' scale used for 'SPACE' interval
23 static const double SPACE_RANGE_EXPONENT = 0.05;
24 
25 ccSubsamplingDlg::ccSubsamplingDlg(unsigned maxPointCount,
26  double maxCloudRadius,
27  QWidget* parent /*=0*/)
28  : QDialog(parent, Qt::Tool),
29  Ui::SubsamplingDialog(),
30  m_maxPointCount(maxPointCount),
31  m_maxRadius(maxCloudRadius),
32  m_sfModEnabled(false),
33  m_sfMin(0),
34  m_sfMax(0) {
35  setupUi(this);
36 
37  samplingMethod->addItem("Random");
38  samplingMethod->addItem("Space");
39  samplingMethod->addItem("Octree");
40 
41  connect(slider, &QSlider::sliderMoved, this,
43  connect(samplingValue,
44  static_cast<void (QDoubleSpinBox::*)(double)>(
45  &QDoubleSpinBox::valueChanged),
47  connect(samplingMethod,
48  static_cast<void (QComboBox::*)(int)>(
49  &QComboBox::currentIndexChanged),
51 
52  samplingMethod->setCurrentIndex(1);
53  sliderMoved(slider->sliderPosition());
54 }
55 
57  ccGenericPointCloud* cloud,
58  cloudViewer::GenericProgressCallback* progressCb /*=0*/) {
59  if (!cloud || cloud->size() == 0) {
61  "[ccSubsamplingDlg::getSampledCloud] Invalid input cloud!");
62  return nullptr;
63  }
64 
65  switch (samplingMethod->currentIndex()) {
66  case RANDOM: {
67  assert(samplingValue->value() >= 0);
68  unsigned count = static_cast<unsigned>(samplingValue->value());
70  cloud, count, progressCb);
71  } break;
72 
73  case SPACE: {
75  if (!octree) octree = cloud->computeOctree(progressCb);
76  if (octree) {
77  PointCoordinateType minDist = static_cast<PointCoordinateType>(
78  samplingValue->value());
80  modParams.enabled =
81  sfGroupBox->isEnabled() && sfGroupBox->isChecked();
82  if (modParams.enabled) {
83  double deltaSF = static_cast<double>(m_sfMax - m_sfMin);
84  assert(deltaSF >= 0);
85  if (cloudViewer::GreaterThanEpsilon(deltaSF)) {
86  double sfMinSpacing =
87  minSFSpacingDoubleSpinBox->value();
88  double sfMaxSpacing =
89  maxSFSpacingDoubleSpinBox->value();
90  modParams.a = (sfMaxSpacing - sfMinSpacing) / deltaSF;
91  modParams.b =
92  sfMinSpacing -
93  modParams.a * static_cast<double>(m_sfMin);
94  } else {
95  modParams.a = 0.0;
96  modParams.b = static_cast<double>(m_sfMin);
97  }
98  }
100  cloud, minDist, modParams, octree.data(), progressCb);
101  } else {
103  QString("[ccSubsamplingDlg::getSampledCloud] Failed to "
104  "compute octree for cloud '%1'")
105  .arg(cloud->getName()));
106  }
107  } break;
108 
109  case OCTREE: {
110  ccOctree::Shared octree = cloud->getOctree();
111  if (!octree) octree = cloud->computeOctree(progressCb);
112  if (octree) {
113  assert(samplingValue->value() >= 0);
114  unsigned char level =
115  static_cast<unsigned char>(samplingValue->value());
118  cloud, level,
120  NEAREST_POINT_TO_CELL_CENTER,
121  progressCb, octree.data());
122  } else {
124  QString("[ccSubsamplingDlg::getSampledCloud] Failed to "
125  "compute octree for cloud '%1'")
126  .arg(cloud->getName()));
127  }
128  } break;
129  }
130 
131  // something went wrong!
132  return nullptr;
133 }
134 
136  switch (samplingMethod->currentIndex()) {
137  case RANDOM:
138  labelSliderMin->setText("none");
139  labelSliderMax->setText("all");
140  valueLabel->setText("remaining points");
141  break;
142  case SPACE:
143  labelSliderMin->setText("large");
144  labelSliderMax->setText("small");
145  valueLabel->setText("min. space between points");
146  break;
147  case OCTREE:
148  labelSliderMin->setText("min");
149  labelSliderMax->setText("max");
150  valueLabel->setText("subdivision level");
151  break;
152  default:
153  break;
154  }
155 }
156 
157 void ccSubsamplingDlg::sliderMoved(int sliderPos) {
158  double sliderRange =
159  static_cast<double>(slider->maximum() - slider->minimum());
160  double rate = static_cast<double>(sliderPos) / sliderRange;
161  if (samplingMethod->currentIndex() == SPACE) {
162  rate = pow(rate, SPACE_RANGE_EXPONENT);
163  rate = 1.0 - rate;
164  }
165 
166  double valueRange = static_cast<double>(samplingValue->maximum() -
167  samplingValue->minimum());
168  samplingValue->setValue(samplingValue->minimum() + rate * valueRange);
169 }
170 
172  double valueRange = static_cast<double>(samplingValue->maximum() -
173  samplingValue->minimum());
174  double rate =
175  static_cast<double>(value - samplingValue->minimum()) / valueRange;
176 
177  CC_SUBSAMPLING_METHOD method =
178  static_cast<CC_SUBSAMPLING_METHOD>(samplingMethod->currentIndex());
179  if (method == SPACE) {
180  rate = 1.0 - rate;
181  rate = pow(rate, 1.0 / SPACE_RANGE_EXPONENT);
182 
183  if (m_sfModEnabled && !sfGroupBox->isChecked()) {
184  minSFSpacingDoubleSpinBox->setValue(value);
185  maxSFSpacingDoubleSpinBox->setValue(value);
186  }
187  }
188 
189  slider->blockSignals(true);
190  double sliderRange =
191  static_cast<double>(slider->maximum() - slider->minimum());
192  slider->setSliderPosition(slider->minimum() +
193  static_cast<int>(rate * sliderRange));
194  slider->blockSignals(false);
195 }
196 
198  int oldSliderPos = slider->sliderPosition();
199  sfGroupBox->setEnabled(false);
200 
201  // update the labels
202  samplingValue->blockSignals(true);
203  switch (index) {
204  case RANDOM: {
205  samplingValue->setDecimals(0);
206  samplingValue->setMinimum(1);
207  samplingValue->setMaximum(static_cast<double>(m_maxPointCount));
208  samplingValue->setSingleStep(1);
209  samplingValue->setEnabled(true);
210  } break;
211  case SPACE: {
212  samplingValue->setDecimals(4);
213  samplingValue->setMinimum(0.0);
214  samplingValue->setMaximum(m_maxRadius);
215  double step = m_maxRadius / 1000.0;
216  samplingValue->setSingleStep(step);
217  minSFSpacingDoubleSpinBox->setMaximum(m_maxRadius);
218  minSFSpacingDoubleSpinBox->setSingleStep(step);
219  maxSFSpacingDoubleSpinBox->setMaximum(m_maxRadius);
220  maxSFSpacingDoubleSpinBox->setSingleStep(step);
221  sfGroupBox->setEnabled(m_sfModEnabled);
222  samplingValue->setDisabled(sfGroupBox->isEnabled() &&
223  sfGroupBox->isChecked());
224  } break;
225  case OCTREE: {
226  samplingValue->setDecimals(0);
227  samplingValue->setMinimum(1);
228  samplingValue->setMaximum(static_cast<double>(
230  samplingValue->setSingleStep(1);
231  samplingValue->setEnabled(true);
232  } break;
233  default:
234  break;
235  }
236  samplingValue->blockSignals(false);
237 
238  updateLabels();
239  // slider->setSliderPosition(oldSliderPos);
240  sliderMoved(oldSliderPos);
241 }
242 
243 void ccSubsamplingDlg::enableSFModulation(ScalarType sfMin, ScalarType sfMax) {
246  if (!m_sfModEnabled) {
248  "[ccSubsamplingDlg::enableSFModulation] Invalid input SF "
249  "values");
250  return;
251  }
252 
253  m_sfMin = sfMin;
254  m_sfMax = sfMax;
255 
256  sfGroupBox->setEnabled(samplingMethod->currentIndex() == SPACE);
257  minSFlabel->setText(QString::number(sfMin));
258  maxSFlabel->setText(QString::number(sfMax));
259 }
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int count
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual ccOctree::Shared computeOctree(cloudViewer::GenericProgressCallback *progressCb=nullptr, bool autoAddChild=true)
Computes the cloud octree.
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
QSharedPointer< ccOctree > Shared
Shared pointer.
Definition: ecvOctree.h:32
ccSubsamplingDlg(unsigned maxPointCount, double maxCloudRadius, QWidget *parent=0)
Default constructor.
cloudViewer::ReferenceCloud * getSampledCloud(ccGenericPointCloud *cloud, cloudViewer::GenericProgressCallback *progressCb=0)
Returns subsampled version of a cloud according to current parameters.
CC_SUBSAMPLING_METHOD
Sub-sampling method.
void enableSFModulation(ScalarType sfMin, ScalarType sfMax)
Enables the SF modulation option (SPATIAL method)
ScalarType m_sfMax
Scalar modulation (max SF value)
void updateLabels()
Updates the dialog labels depending on the active mode.
ScalarType m_sfMin
Scalar modulation (min SF value)
void samplingRateChanged(double value)
void changeSamplingMethod(int index)
void sliderMoved(int sliderPos)
bool m_sfModEnabled
Scalar modulation.
unsigned m_maxPointCount
Max point count (for RANDOM method)
double m_maxRadius
Max radius (for SPACE method)
Several point cloud resampling algorithms (octree-based, random, etc.)
static ReferenceCloud * subsampleCloudRandomly(GenericIndexedCloudPersist *cloud, unsigned newNumberOfPoints, GenericProgressCallback *progressCb=nullptr)
Subsamples a point cloud (process based on random selections)
static ReferenceCloud * subsampleCloudWithOctreeAtLevel(GenericIndexedCloudPersist *cloud, unsigned char octreeLevel, SUBSAMPLING_CELL_METHOD subsamplingMethod, GenericProgressCallback *progressCb=nullptr, DgmOctree *inputOctree=nullptr)
Subsamples a point cloud (process based on the octree)
static ReferenceCloud * resampleCloudSpatially(GenericIndexedCloudPersist *cloud, PointCoordinateType minDistance, const SFModulationParams &modParams, DgmOctree *octree=nullptr, GenericProgressCallback *progressCb=nullptr)
Resamples a point cloud (process based on inter point distance)
static const int MAX_OCTREE_LEVEL
Max octree subdivision level.
Definition: DgmOctree.h:67
virtual unsigned size() const =0
Returns the number of points.
A very simple point cloud (no point duplication)
static bool ValidValue(ScalarType value)
Returns whether a scalar value is valid or not.
Definition: ScalarField.h:61
static const double SPACE_RANGE_EXPONENT
bool GreaterThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
Definition: CVMath.h:37
cloudViewer::DgmOctree * octree
Parameters for the scalar-field based modulation of a parameter.
bool enabled
Whether the modulation is enabled or not.
double b
Modulation scheme: y = a.sf + b.
double a
Modulation scheme: y = a.sf + b.