ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
qCanupoTrainingDialog.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 // local
11 #include "ccPointDescriptor.h"
12 #include "qCanupoTools.h"
13 
14 // CV_DB_LIB
15 #include <ecvMainAppInterface.h>
16 #include <ecvPointCloud.h>
17 
18 // Qt
19 #include <QApplication>
20 #include <QComboBox>
21 #include <QMainWindow>
22 #include <QPushButton>
23 #include <QSettings>
24 #include <QThread>
25 
26 // Qt5/Qt6 Compatibility
27 #include <QtCompat.h>
28 
29 // system
30 #include <limits>
31 
33  : QDialog(app ? app->getActiveWindow() : 0),
34  Ui::CanupoTrainingDialog(),
35  m_app(app) {
36  setupUi(this);
37 
38  int maxThreadCount = QThread::idealThreadCount();
39  maxThreadCountSpinBox->setRange(1, maxThreadCount);
40  maxThreadCountSpinBox->setSuffix(QString(" / %1").arg(maxThreadCount));
41 
42  if (m_app) {
43  // add list of clouds to the combo-boxes
44  ccHObject::Container clouds;
45  if (m_app->dbRootObject())
46  m_app->dbRootObject()->filterChildren(clouds, true,
48 
49  unsigned cloudCount = 0;
50  for (size_t i = 0; i < clouds.size(); ++i) {
51  if (clouds[i]->isA(CV_TYPES::POINT_CLOUD)) // as filterChildren
52  // only test 'isKindOf'
53  {
54  QString name = qCanupoTools::GetEntityName(clouds[i]);
55  QVariant uniqueID(clouds[i]->getUniqueID());
56  originCloudComboBox->addItem(name, uniqueID);
57  class1CloudComboBox->addItem(name, uniqueID);
58  class2CloudComboBox->addItem(name, uniqueID);
59  evaluationCloudComboBox->addItem(name, uniqueID);
60  ++cloudCount;
61  }
62  }
63 
64  // if 3 clouds are loaded, then there's chances that the first one is
65  // the global cloud!
66  class1CloudComboBox->setCurrentIndex(
67  cloudCount > 0 ? (cloudCount > 2 ? 1 : 0) : -1);
68  class2CloudComboBox->setCurrentIndex(
69  cloudCount > 1 ? (cloudCount > 2 ? 2 : 1) : -1);
70  originCloudComboBox->setCurrentIndex(cloudCount > 2 ? 0 : -1);
71 
72  if (cloudCount < 2 && app)
73  app->dispToConsole(
74  "You need at least 2 loaded clouds to train a classifier "
75  "(one per class)",
77  }
78 
79  // add the list of available descriptors
80  {
81  paramComboBox->clear();
83  for (unsigned i = 0; i < count; ++i) {
85  paramComboBox->addItem(scp->getName(), scp->getID());
86  }
87  }
88 
90 
91  connect(cloud1ClassSpinBox, SIGNAL(valueChanged(int)), this,
92  SLOT(onClassChanged(int)));
93  connect(cloud2ClassSpinBox, SIGNAL(valueChanged(int)), this,
94  SLOT(onClassChanged(int)));
95  connect(class1CloudComboBox, SIGNAL(currentIndexChanged(int)), this,
96  SLOT(onCloudChanged(int)));
97  connect(class2CloudComboBox, SIGNAL(currentIndexChanged(int)), this,
98  SLOT(onCloudChanged(int)));
99 
100  onClassChanged(0);
101  onCloudChanged(0);
102 }
103 
105  if (cloud1ClassSpinBox->value() == cloud2ClassSpinBox->value())
106  return false;
107 
108  int c1 = class1CloudComboBox->currentIndex();
109  int c2 = class2CloudComboBox->currentIndex();
110  if (c1 < 0 || c2 < 0) return false;
111  if (c1 == c2) return false;
112 
113  return true;
114 }
115 
117  return maxThreadCountSpinBox->value();
118 }
119 
120 bool qCanupoTrainingDialog::getScales(std::vector<float>& scales) const {
121  scales.clear();
122 
123  try {
124  if (scalesRampRadioButton->isChecked()) {
125  double maxScale = maxScaleDoubleSpinBox->value();
126  double step = stepScaleDoubleSpinBox->value();
127  double minScale = minScaleDoubleSpinBox->value();
128  if (maxScale < minScale || maxScale < 0 || step < 1.0e-6)
129  return false;
130  unsigned stepCount =
131  static_cast<unsigned>(
132  floor((maxScale - minScale) / step + 1.0e-6)) +
133  1;
134  scales.resize(stepCount);
135  for (unsigned i = 0; i < stepCount; ++i)
136  scales[i] = static_cast<float>(maxScale - i * step);
137  } else if (scalesListRadioButton->isChecked()) {
138  QStringList scaleList = scalesListLineEdit->text().split(
140 
141  int listSize = scaleList.size();
142  scales.resize(listSize);
143  for (int i = 0; i < listSize; ++i) {
144  bool ok = false;
145  float f;
146  f = scaleList[i].toFloat(&ok);
147  if (!ok) return false;
148  scales[i] = f;
149  }
150  } else {
151  return false;
152  }
153  } catch (const std::bad_alloc&) {
154  return false;
155  }
156 
157  return true;
158 }
159 
161  // paramComboBox
162  int currentIndex = paramComboBox->currentIndex();
163  if (currentIndex < 0) {
164  assert(false);
165  return 0;
166  }
167 
168  return paramComboBox->itemData(currentIndex).toUInt();
169 }
170 
172  buttonBox->button(QDialogButtonBox::Ok)->setEnabled(validParameters());
173 }
174 
176  buttonBox->button(QDialogButtonBox::Ok)->setEnabled(validParameters());
177 }
178 
180  // return the cloud currently selected in the combox box
181  return qCanupoTools::GetCloudFromCombo(class1CloudComboBox,
182  m_app->dbRootObject());
183 }
184 
186  // return the cloud currently selected in the combox box
187  return qCanupoTools::GetCloudFromCombo(class2CloudComboBox,
188  m_app->dbRootObject());
189 }
190 
192  // return the cloud currently selected in the combox box
193  return useOriginalCloudCheckBox->isChecked()
194  ? qCanupoTools::GetCloudFromCombo(originCloudComboBox,
195  m_app->dbRootObject())
196  : 0;
197 }
198 
200  // return the cloud currently selected in the combox box
201  return evaluateParamsCheckBox->isChecked()
202  ? qCanupoTools::GetCloudFromCombo(evaluationCloudComboBox,
203  m_app->dbRootObject())
204  : 0;
205 }
206 
208  QSettings settings("qCanupo");
209  settings.beginGroup("Training");
210 
211  // read out parameters
212  double minScale = settings.value("MinScale", minScaleDoubleSpinBox->value())
213  .toDouble();
214  double step =
215  settings.value("Step", stepScaleDoubleSpinBox->value()).toDouble();
216  double maxScale = settings.value("MaxScale", maxScaleDoubleSpinBox->value())
217  .toDouble();
218  QString scalesList =
219  settings.value("ScalesList", scalesListLineEdit->text()).toString();
220  bool scalesRampEnabled = settings.value("ScalesRampEnabled",
221  scalesRampRadioButton->isChecked())
222  .toBool();
223 
224  unsigned maxPoints =
225  settings.value("MaxPoints", maxPointsSpinBox->value()).toUInt();
226  int classifParam =
227  settings.value("ClassifParam", paramComboBox->currentIndex())
228  .toInt();
229  int maxThreadCount =
230  settings.value("MaxThreadCount", maxThreadCountSpinBox->maximum())
231  .toInt();
232 
233  // apply parameters
234 
235  minScaleDoubleSpinBox->setValue(minScale);
236  stepScaleDoubleSpinBox->setValue(step);
237  maxScaleDoubleSpinBox->setValue(maxScale);
238  scalesListLineEdit->setText(scalesList);
239  if (scalesRampEnabled)
240  scalesRampRadioButton->setChecked(true);
241  else
242  scalesListRadioButton->setChecked(true);
243 
244  maxPointsSpinBox->setValue(maxPoints);
245  paramComboBox->setCurrentIndex(classifParam);
246  maxThreadCountSpinBox->setValue(maxThreadCount);
247 }
248 
250  QSettings settings("qCanupo");
251  settings.beginGroup("Training");
252 
253  // save parameters
254  settings.setValue("MinScale", minScaleDoubleSpinBox->value());
255  settings.setValue("Step", stepScaleDoubleSpinBox->value());
256  settings.setValue("MaxScale", maxScaleDoubleSpinBox->value());
257  settings.setValue("ScalesList", scalesListLineEdit->text());
258  settings.setValue("ScalesRampEnabled", scalesRampRadioButton->isChecked());
259 
260  settings.setValue("MaxPoints", maxPointsSpinBox->value());
261  settings.setValue("ClassifParam", paramComboBox->currentIndex());
262  settings.setValue("MaxThreadCount", maxThreadCountSpinBox->value());
263 }
std::string name
int count
Generic parameters 'computer' class (at a given scale)
static unsigned AvailableCount()
Returns the number of available 'descriptors'.
static ScaleParamsComputer * GetByIndex(unsigned index)
Vault: returns the ith computer.
virtual unsigned getID() const =0
Returns the associated descriptor ID.
virtual QString getName() const =0
Returns the associated descriptor name.
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
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
static ccPointCloud * GetCloudFromCombo(QComboBox *comboBox, ccHObject *dbRoot)
static QString GetEntityName(ccHObject *obj)
Returns a long description of a given entity (name + [ID])
ccPointCloud * getEvaluationCloud()
Get evaluation point cloud.
bool getScales(std::vector< float > &scales) const
Returns input scales.
ccPointCloud * getClass1Cloud()
Get class #1 point cloud.
void saveParamsToPersistentSettings()
Saves parameters to persistent settings.
qCanupoTrainingDialog(ecvMainAppInterface *app)
Default constructor.
unsigned getDescriptorID() const
Returns the selected descriptor ID.
ecvMainAppInterface * m_app
Gives access to the application (data-base, UI, etc.)
void loadParamsFromPersistentSettings()
Loads parameters from persistent settings.
ccPointCloud * getOriginPointCloud()
Get origin point cloud.
int getMaxThreadCount() const
Returns the max number of threads to use.
ccPointCloud * getClass2Cloud()
Get class #2 point cloud.
@ 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