ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvRegistrationDlg.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 "ecvRegistrationDlg.h"
9 
10 // Local
11 #include "MainWindow.h"
12 
13 // common
14 #include <ecvQtHelpers.h>
15 
16 // cloudViewer
17 #include <CloudSamplingTools.h>
18 #include <DgmOctree.h>
20 #include <ReferenceCloud.h>
21 
22 // CV_DB_LIB
23 #include <ecvDisplayTools.h>
24 #include <ecvHObject.h>
25 
26 // Qt
27 #include <QThread>
28 
29 // system
30 #include <assert.h>
31 
32 static bool s_adjustScale = false;
33 static unsigned s_randomSamplingLimit = 50000;
34 static double s_rmsDifference = 1.0e-5;
35 static int s_maxIterationCount = 20;
36 static bool s_useErrorDifferenceCriterion = true;
37 static int s_finalOverlap = 100;
38 static int s_rotComboIndex = 0;
39 static bool s_transCheckboxes[3] = {true, true, true};
40 static int s_maxThreadCount = 0;
41 static bool s_pointsRemoval = false;
42 static bool s_useDataSFAsWeights = false;
43 static bool s_useModelSFAsWeights = false;
44 static bool s_useC2MSignedDistances = false;
47 
49  ccHObject *model,
50  QWidget *parent /*=nullptr*/)
51  : QDialog(parent, Qt::Tool), Ui::RegistrationDialog() {
52  assert(data && model);
53  dataEntity = data;
54  modelEntity = model;
55 
56  setupUi(this);
57 
58  QDoubleValidator *rmsValidator =
59  new QDoubleValidator(rmsDifferenceLineEdit);
60  rmsValidator->setNotation(QDoubleValidator::ScientificNotation);
61  rmsValidator->setRange(GetAbsoluteMinRMSDecrease(), 1.0, 1);
62  rmsDifferenceLineEdit->setValidator(rmsValidator);
63 
64  updateGUI();
65 
66  ccQtHelpers::SetButtonColor(dataColorButton, Qt::red);
67  ccQtHelpers::SetButtonColor(modelColorButton, Qt::yellow);
68 
69  int idealThreadCount = QThread::idealThreadCount();
70  maxThreadCountSpinBox->setRange(1, idealThreadCount);
71  maxThreadCountSpinBox->setSuffix(QString(" / %1").arg(idealThreadCount));
72 
73  // restore semi-persistent settings
74  {
75  // semi-persistent options
76  if (s_maxThreadCount == 0) {
77  s_maxThreadCount = idealThreadCount;
78  }
79  maxThreadCountSpinBox->setValue(s_maxThreadCount);
80  adjustScaleCheckBox->setChecked(s_adjustScale);
81  randomSamplingLimitSpinBox->setValue(s_randomSamplingLimit);
83  maxIterationCount->setValue(s_maxIterationCount);
85  errorCriterion->setChecked(true);
86  else
87  iterationsCriterion->setChecked(true);
88  overlapSpinBox->setValue(s_finalOverlap);
89  rotComboBox->setCurrentIndex(s_rotComboIndex);
90  TxCheckBox->setChecked(s_transCheckboxes[0]);
91  TyCheckBox->setChecked(s_transCheckboxes[1]);
92  TzCheckBox->setChecked(s_transCheckboxes[2]);
93  pointsRemoval->setChecked(s_pointsRemoval);
94  checkBoxUseDataSFAsWeights->setChecked(s_useDataSFAsWeights);
95  checkBoxUseModelSFAsWeights->setChecked(s_useModelSFAsWeights);
96  useC2MSignedDistancesCheckBox->setChecked(s_useC2MSignedDistances);
97  normalsComboBox->setCurrentIndex(s_normalsMatchingOption);
98  }
99 
100  connect(swapButton, &QAbstractButton::clicked, this,
102 }
103 
105  if (modelEntity) {
107  }
108  if (dataEntity) {
109  dataEntity->enableTempColor(false);
110  }
111 
114 }
115 
122  s_useErrorDifferenceCriterion = errorCriterion->isChecked();
123  s_finalOverlap = overlapSpinBox->value();
124  s_rotComboIndex = rotComboBox->currentIndex();
125  s_transCheckboxes[0] = TxCheckBox->isChecked();
126  s_transCheckboxes[1] = TyCheckBox->isChecked();
127  s_transCheckboxes[2] = TzCheckBox->isChecked();
129  s_useDataSFAsWeights = checkBoxUseDataSFAsWeights->isChecked();
130  s_useModelSFAsWeights = checkBoxUseModelSFAsWeights->isChecked();
131  s_useC2MSignedDistances = useC2MSignedDistancesCheckBox->isChecked();
132  s_normalsMatchingOption = normalsComboBox->currentIndex();
133 }
134 
136 
138 
140  return checkBoxUseDataSFAsWeights->isEnabled() &&
141  checkBoxUseDataSFAsWeights->isChecked();
142 }
143 
145  return checkBoxUseModelSFAsWeights->isEnabled() &&
146  checkBoxUseModelSFAsWeights->isChecked();
147 }
148 
150  return useC2MSignedDistancesCheckBox->isEnabled() &&
151  useC2MSignedDistancesCheckBox->isChecked();
152 }
153 
156  if (normalsComboBox->isEnabled()) {
158  normalsComboBox->currentIndex());
159  } else {
161  }
162 }
163 
165  return adjustScaleCheckBox->isChecked();
166 }
167 
169  return pointsRemoval->isChecked();
170 }
171 
173  return randomSamplingLimitSpinBox->value();
174 }
175 
177  return static_cast<unsigned>(std::max(1, maxIterationCount->value()));
178 }
179 
181  return static_cast<unsigned>(std::max(10, overlapSpinBox->value()));
182 }
183 
185  return maxThreadCountSpinBox->value();
186 }
187 
189 
191  bool ok = true;
192  double val = rmsDifferenceLineEdit->text().toDouble(&ok);
193 
194  if (!ok) {
195  assert(false);
196  val = std::numeric_limits<double>::quiet_NaN();
197  }
198 
199  return val;
200 }
201 
203  if (std::isnan(value)) {
204  // last input value was invalid, restoring default
205  value = 1.0e-5;
206  }
207  rmsDifferenceLineEdit->setText(QString::number(value, 'E', 1));
208 }
209 
211  const {
212  if (errorCriterion->isChecked())
214  else
216 }
217 
219  int filters = 0;
220  switch (rotComboBox->currentIndex()) {
221  case 1:
223  break;
224  case 2:
226  break;
227  case 3:
229  break;
230  default:
231  // nothing to do
232  break;
233  }
234 
235  if (!TxCheckBox->isChecked())
237  if (!TyCheckBox->isChecked())
239  if (!TzCheckBox->isChecked())
241 
242  return filters;
243 }
244 
246  if (!modelEntity || !dataEntity) return;
247 
248  modelLineEdit->setText(modelEntity->getName());
249  modelEntity->setVisible(true);
251 
252  dataLineEdit->setText(dataEntity->getName());
253  dataEntity->setVisible(true);
255 
256  checkBoxUseDataSFAsWeights->setEnabled(
258  checkBoxUseModelSFAsWeights->setEnabled(
261  ->hasDisplayedScalarField()); // only supported for clouds
262 
263  useC2MSignedDistancesCheckBox->setEnabled(
264  modelEntity->isKindOf(CV_TYPES::MESH)); // only supported if a mesh
265  // is the reference cloud
266  normalsComboBox->setEnabled(
267  dataEntity->hasNormals() &&
269  ->hasNormals()); // only supported if both the aligned and
270  // the reference entities have normals
271 
274 }
275 
278  updateGUI();
279 }
virtual void setTempColor(const ecvColor::Rgb &col, bool autoActivate=true)
Sets current temporary (unique)
virtual bool hasDisplayedScalarField() const
Returns whether an active scalar field is available or not.
virtual void setVisible(bool state)
Sets entity visibility.
virtual bool hasNormals() const
Returns whether normals are enabled or not.
virtual void enableTempColor(bool state)
Set temporary color activation state.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
bool isKindOf(CV_CLASS_ENUM type) const
Definition: ecvObject.h:128
static void SetButtonColor(QAbstractButton *button, const QColor &col)
Sets a button background color.
Definition: ecvQtHelpers.h:17
void saveParameters() const
Saves parameters for next call.
bool useC2MSignedDistances() const
Whether to use signed distances when the reference is a mesh.
bool useModelSFAsWeights() const
Whether to use model displayed SF as weights.
unsigned getFinalOverlap() const
Returns the approximated final overlap.
bool adjustScale() const
Returns whether to adjust the scale during optimization.
unsigned randomSamplingLimit() const
Returns the limit above which clouds should be randomly resampled.
virtual ~ccRegistrationDlg()
Default destructor.
unsigned getMaxIterationCount() const
Returns max number of iterations.
bool useDataSFAsWeights() const
Whether to use data displayed SF as weights.
ccHObject * modelEntity
'Model' entity
static double GetAbsoluteMinRMSDecrease()
ccHObject * getModelEntity()
Returns 'model' entity.
ccHObject * getDataEntity()
Returns 'data' entity.
double getMinRMSDecrease() const
Returns minimum RMS decrease between two consecutive iterations.
cloudViewer::ICPRegistrationTools::NORMALS_MATCHING normalsMatchingOption() const
Method to take normals into account.
int getMaxThreadCount() const
Returns the maximum number of threads.
ccRegistrationDlg(ccHObject *data, ccHObject *model, QWidget *parent=nullptr)
Default constructor.
void setMinRMSDecrease(double value)
Sets the minimum RMS decrease between two consecutive iterations.
bool removeFarthestPoints() const
Returns whether farthest points should be ignored at each iteration.
ccHObject * dataEntity
'Data' entity
ConvergenceMethod getConvergenceMethod() const
Returns convergence method.
int getTransformationFilters() const
Returns active transformation filters.
CONVERGENCE_TYPE
Convergence control method.
NORMALS_MATCHING
Normals matching method.
static void SetRedrawRecursive(bool redraw=false)
static void RedrawDisplay(bool only2D=false, bool forceRedraw=true)
int max(int a, int b)
Definition: cutil_math.h:48
static int s_rotComboIndex
static int s_maxIterationCount
static bool s_useDataSFAsWeights
static int s_finalOverlap
static int s_normalsMatchingOption
static int s_maxThreadCount
static bool s_adjustScale
static bool s_useModelSFAsWeights
static bool s_useErrorDifferenceCriterion
static bool s_useC2MSignedDistances
static unsigned s_randomSamplingLimit
static bool s_transCheckboxes[3]
static double s_rmsDifference
static bool s_pointsRemoval
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
constexpr Rgb red(MAX, 0, 0)
constexpr Rgb yellow(MAX, MAX, 0)
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Definition: SmallVector.h:1370