ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
CorrespondenceMatchingDialog.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 
9 
10 // CV_DB_LIB
11 #include <ecvMainAppInterface.h>
12 #include <ecvPointCloud.h>
13 
14 // Qt
15 #include <QApplication>
16 #include <QComboBox>
17 #include <QMainWindow>
18 #include <QPushButton>
19 #include <QSettings>
20 #include <QThread>
21 
22 // Qt5/Qt6 Compatibility
23 #include <QtCompat.h>
24 
25 // system
26 #include <limits>
27 
30  : QDialog(app ? app->getActiveWindow() : 0),
32  m_app(app) {
33  setupUi(this);
34 
35  int maxThreadCount = QThread::idealThreadCount();
36  maxThreadCountSpinBox->setRange(1, maxThreadCount);
37  maxThreadCountSpinBox->setSuffix(QString("/%1").arg(maxThreadCount));
38  maxThreadCountSpinBox->setValue(maxThreadCount);
39 
41 
42  connect(model1CloudComboBox, SIGNAL(currentIndexChanged(int)), this,
43  SLOT(onCloudChanged(int)));
44  connect(model2CloudComboBox, SIGNAL(currentIndexChanged(int)), this,
45  SLOT(onCloudChanged(int)));
46 
47  onCloudChanged(0);
48 }
49 
51  if (m_app) {
52  // add list of clouds to the combo-boxes
53  ccHObject::Container clouds;
54  if (m_app->dbRootObject())
55  m_app->dbRootObject()->filterChildren(clouds, true,
57 
58  unsigned cloudCount = 0;
59  model1CloudComboBox->clear();
60  model2CloudComboBox->clear();
61  evaluationCloudComboBox->clear();
62  for (size_t i = 0; i < clouds.size(); ++i) {
63  if (clouds[i]->isA(CV_TYPES::POINT_CLOUD)) // as filterChildren
64  // only test 'isKindOf'
65  {
66  QString name = getEntityName(clouds[i]);
67  QVariant uniqueID(clouds[i]->getUniqueID());
68  model1CloudComboBox->addItem(name, uniqueID);
69  model2CloudComboBox->addItem(name, uniqueID);
70  evaluationCloudComboBox->addItem(name, uniqueID);
71  ++cloudCount;
72  }
73  }
74 
75  // if 3 clouds are loaded, then there's chances that the first one is
76  // the global cloud!
77  model1CloudComboBox->setCurrentIndex(
78  cloudCount > 0 ? (cloudCount > 2 ? 1 : 0) : -1);
79  model2CloudComboBox->setCurrentIndex(
80  cloudCount > 1 ? (cloudCount > 2 ? 2 : 1) : -1);
81 
82  if (cloudCount < 1 && m_app)
84  tr("You need at least 1 loaded clouds to perform matching"),
86  }
87 }
88 
90  int c1 = model1CloudComboBox->currentIndex();
91  if (model1checkBox->isChecked()) {
92  if (c1 < 0) {
93  return false;
94  }
95  }
96  int c2 = model2CloudComboBox->currentIndex();
97  if (model2checkBox->isChecked()) {
98  if (c2 < 0) {
99  return false;
100  }
101  }
102 
103  if (model1checkBox->isChecked() && model2checkBox->isChecked()) {
104  if (c1 == c2) return false;
105  }
106 
107  return true;
108 }
109 
111  return maxThreadCountSpinBox->value();
112 }
113 
115  return verificationCheckBox->isChecked();
116 }
117 
119  return static_cast<float>(modelSearchRadiusSpinBox->value());
120 }
121 
123  return static_cast<float>(sceneSearchRadiusSpinBox->value());
124 }
125 
127  return static_cast<float>(shotDescriptorRadiusSpinBox->value());
128 }
129 
131  return static_cast<float>(normalKSearchSpinBox->value());
132 }
133 
135  return GCcheckBox->isChecked() ? true : false;
136 }
137 
139  return static_cast<float>(gcResolutionSpinBox->value());
140 }
141 
143  return static_cast<float>(gcMinClusterSizeSpinBox->value());
144 }
145 
147  return static_cast<float>(LRFRadiusSpinBox->value());
148 }
149 
151  return static_cast<float>(houghBinSizeSpinBox->value());
152 }
153 
155  return static_cast<float>(houghThresholdSpinBox->value());
156 }
157 
159  if (useVoxelGridCheckBox->isChecked()) {
160  return static_cast<float>(leafSizeSpinBox->value());
161  } else {
162  return -1.0f;
163  }
164 }
165 
166 bool CorrespondenceMatchingDialog::getScales(std::vector<float>& scales) const {
167  scales.clear();
168 
169  try {
170  if (scalesRampRadioButton->isChecked()) {
171  double maxScale = maxScaleDoubleSpinBox->value();
172  double step = stepScaleDoubleSpinBox->value();
173  double minScale = minScaleDoubleSpinBox->value();
174  if (maxScale < minScale || maxScale < 0 || step < 1.0e-6)
175  return false;
176  unsigned stepCount =
177  static_cast<unsigned>(
178  floor((maxScale - minScale) / step + 1.0e-6)) +
179  1;
180  scales.resize(stepCount);
181  for (unsigned i = 0; i < stepCount; ++i)
182  scales[i] = static_cast<float>(maxScale - i * step);
183  } else if (scalesListRadioButton->isChecked()) {
184  QStringList scaleList = scalesListLineEdit->text().split(
186 
187  int listSize = scaleList.size();
188  scales.resize(listSize);
189  for (int i = 0; i < listSize; ++i) {
190  bool ok = false;
191  float f;
192  f = scaleList[i].toFloat(&ok);
193  if (!ok) return false;
194  scales[i] = f;
195  }
196  } else {
197  return false;
198  }
199  } catch (const std::bad_alloc&) {
200  return false;
201  }
202 
203  return true;
204 }
205 
207  buttonBox->button(QDialogButtonBox::Ok)->setEnabled(validParameters());
208 }
209 
211  // return the cloud currently selected in the combox box
212  if (model1checkBox->isChecked()) {
213  return getCloudFromCombo(model1CloudComboBox, m_app->dbRootObject());
214  } else {
215  return nullptr;
216  }
217 }
218 
220  // return the cloud currently selected in the combox box
221  if (model2checkBox->isChecked()) {
222  return getCloudFromCombo(model2CloudComboBox, m_app->dbRootObject());
223  } else {
224  return nullptr;
225  }
226 }
227 
229  switch (index) {
230  case 1:
231  return getModel1Cloud();
232  break;
233  case 2:
234  return getModel2Cloud();
235  break;
236  default:
237  return nullptr;
238  break;
239  }
240 }
241 
243  // return the cloud currently selected in the combox box
244  return getCloudFromCombo(evaluationCloudComboBox, m_app->dbRootObject());
245 }
246 
248  QSettings settings("templateAlignment");
249  settings.beginGroup("Align");
250 
251  // read out parameters
252  // double minScale =
253  // settings.value("MinScale",minScaleDoubleSpinBox->value()).toDouble();
254  // double step =
255  // settings.value("Step",stepScaleDoubleSpinBox->value()).toDouble(); double
256  // maxScale =
257  // settings.value("MaxScale",maxScaleDoubleSpinBox->value()).toDouble();
258  // QString scalesList =
259  // settings.value("ScalesList",scalesListLineEdit->text()).toString(); bool
260  // scalesRampEnabled =
261  // settings.value("ScalesRampEnabled",scalesRampRadioButton->isChecked()).toBool();
262 
263  // unsigned maxPoints =
264  // settings.value("MaxPoints",maxPointsSpinBox->value()).toUInt(); int
265  // classifParam =
266  // settings.value("ClassifParam",paramComboBox->currentIndex()).toInt(); int
267  // maxThreadCount = settings.value("MaxThreadCount",
268  // maxThreadCountSpinBox->maximum()).toInt();
269 
271 
272  // minScaleDoubleSpinBox->setValue(minScale);
273  // stepScaleDoubleSpinBox->setValue(step);
274  // maxScaleDoubleSpinBox->setValue(maxScale);
275  // scalesListLineEdit->setText(scalesList);
276  // if (scalesRampEnabled)
277  // scalesRampRadioButton->setChecked(true);
278  // else
279  // scalesListRadioButton->setChecked(true);
280 
281  // maxPointsSpinBox->setValue(maxPoints);
282  // paramComboBox->setCurrentIndex(classifParam);
283  // maxThreadCountSpinBox->setValue(maxThreadCount);
284 }
285 
287  QSettings settings("templateAlignment");
288  settings.beginGroup("Align");
289 
290  // save parameters
291  // settings.setValue("MinScale", minScaleDoubleSpinBox->value());
292  // settings.setValue("Step", stepScaleDoubleSpinBox->value());
293  // settings.setValue("MaxScale", maxScaleDoubleSpinBox->value());
294  // settings.setValue("ScalesList", scalesListLineEdit->text());
295  // settings.setValue("ScalesRampEnabled",
296  // scalesRampRadioButton->isChecked());
297 
298  // settings.setValue("MaxPoints", maxPointsSpinBox->value());
299  // settings.setValue("ClassifParam", paramComboBox->currentIndex());
300  // settings.setValue("MaxThreadCount", maxThreadCountSpinBox->value());
301 }
302 
304  if (!obj) {
305  assert(false);
306  return QString();
307  }
308 
309  QString name = obj->getName();
310  if (name.isEmpty()) name = tr("unnamed");
311  name += QString(" [ID %1]").arg(obj->getUniqueID());
312 
313  return name;
314 }
315 
317  QComboBox* comboBox, ccHObject* dbRoot) {
318  assert(comboBox && dbRoot);
319  if (!comboBox || !dbRoot) {
320  assert(false);
321  return nullptr;
322  }
323 
324  // return the cloud currently selected in the combox box
325  int index = comboBox->currentIndex();
326  if (index < 0) {
327  assert(false);
328  return nullptr;
329  }
330  unsigned uniqueID = comboBox->itemData(index).toUInt();
331  ccHObject* item = dbRoot->find(uniqueID);
332  if (!item || !item->isA(CV_TYPES::POINT_CLOUD)) {
333  assert(false);
334  return nullptr;
335  }
336  return static_cast<ccPointCloud*>(item);
337 }
std::string name
CANUPO plugin's training dialog.
void saveParamsToPersistentSettings()
Saves parameters to persistent settings.
void loadParamsFromPersistentSettings()
Loads parameters from persistent settings.
ccPointCloud * getModelCloudByIndex(int index)
ccPointCloud * getModel1Cloud()
Get model #1 point cloud.
float getModelSearchRadius() const
Returns the Model Search Radius.
float getShotDescriptorRadius() const
Returns the Shot Descriptor Radius.
float getNormalKSearch() const
Returns the normal KSearch.
ccPointCloud * getEvaluationCloud()
Get evaluation point cloud.
int getMaxThreadCount() const
Returns the max number of threads to use.
CorrespondenceMatchingDialog(ecvMainAppInterface *app)
Default constructor.
ecvMainAppInterface * m_app
Gives access to the application (data-base, UI, etc.)
bool getScales(std::vector< float > &scales) const
Returns input scales.
ccPointCloud * getCloudFromCombo(QComboBox *comboBox, ccHObject *dbRoot)
float getSceneSearchRadius() const
Returns the Scene Search Radius.
ccPointCloud * getModel2Cloud()
Get model #2 point cloud.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
ccHObject * find(unsigned uniqueID)
Finds an entity in this object hierarchy.
unsigned filterChildren(Container &filteredChildren, bool recursive=false, CV_CLASS_ENUM filter=CV_TYPES::OBJECT, bool strict=false) const
Collects the children corresponding to a certain pattern.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
virtual unsigned getUniqueID() const
Returns object unique ID.
Definition: ecvObject.h:86
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
Main application interface (for plugins)
virtual ccHObject * dbRootObject()=0
Returns DB root (as a ccHObject)
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
@ POINT_CLOUD
Definition: CVTypes.h:104
constexpr Qt::SplitBehavior SkipEmptyParts
Definition: QtCompat.h:302
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75