ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
qCSF.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 "qCSF.h"
9 
10 // Qt
11 #include <QApplication>
12 #include <QComboBox>
13 #include <QElapsedTimer>
14 #include <QMainWindow>
15 #include <QProgressDialog>
16 
17 // Dialog
18 #include "ccCSFDlg.h"
19 
20 // Local
21 #include "qCSFCommands.h"
22 
23 // System
24 #include <assert.h>
25 
26 #include <iostream>
27 #include <string>
28 #include <vector>
29 
30 // CV_DB_LIB
31 #include <ecvGenericPointCloud.h>
32 #include <ecvHObjectCaster.h>
33 #include <ecvMesh.h>
34 #include <ecvOctree.h>
35 #include <ecvPointCloud.h>
36 #include <ecvProgressDialog.h>
37 
38 // CSF
39 #include <CSF.h>
40 
41 qCSF::qCSF(QObject* parent)
42  : QObject(parent),
43  ccStdPluginInterface(":/CC/plugin/qCSF/info.json"),
44  m_action(nullptr) {}
45 
46 void qCSF::onNewSelection(const ccHObject::Container& selectedEntities) {
47  if (m_action)
48  m_action->setEnabled(selectedEntities.size() == 1 &&
49  selectedEntities[0]->isA(CV_TYPES::POINT_CLOUD));
50 }
51 
52 QList<QAction*> qCSF::getActions() {
53  if (!m_action) {
54  m_action = new QAction(getName(), this);
55  m_action->setToolTip(getDescription());
56  m_action->setIcon(getIcon());
57  // connect appropriate signal
58  connect(m_action, &QAction::triggered, this, &qCSF::doAction);
59  }
60 
61  return QList<QAction*>{m_action};
62 }
63 
65  // m_app should have already been initialized by CC when plugin is loaded!
66  //(--> pure internal check)
67  assert(m_app);
68  if (!m_app) return;
69 
70  if (!m_app->haveOneSelection()) {
71  m_app->dispToConsole(tr("Select only one cloud!"),
73  return;
74  }
75 
76  const ccHObject::Container& selectedEntities = m_app->getSelectedEntities();
77 
78  ccHObject* ent = selectedEntities[0];
79  assert(ent);
80  if (!ent || !ent->isA(CV_TYPES::POINT_CLOUD)) {
81  m_app->dispToConsole(tr("Select a real point cloud!"),
83  return;
84  }
85 
86  // to get the point cloud from selected entity.
87  ccPointCloud* pc = static_cast<ccPointCloud*>(ent);
88 
89  // Convert CC point cloud to CSF type
90  unsigned count = pc->size();
91  wl::PointCloud csfPC;
92  try {
93  csfPC.reserve(count);
94  } catch (const std::bad_alloc&) {
95  m_app->dispToConsole(tr("Not enough memory!"),
97  return;
98  }
99  for (unsigned i = 0; i < count; i++) {
100  const CCVector3* P = pc->getPoint(i);
101  wl::Point tmpPoint;
102  // tmpPoint.x = P->x;
103  // tmpPoint.y = P->y;
104  // tmpPoint.z = P->z;
105  tmpPoint.x = P->x;
106  tmpPoint.y = -P->z;
107  tmpPoint.z = P->y;
108  csfPC.push_back(tmpPoint);
109  }
110 
111  // initial dialog parameters
112  static bool csf_postprocessing = false;
113  static double cloth_resolution = 2;
114  static double class_threshold = 0.5;
115  static int csf_rigidness = 2;
116  static int MaxIteration = 500;
117  static bool ExportClothMesh = false;
118 
119  // display the dialog
120  {
121  ccCSFDlg csfDlg(m_app->getMainWindow());
122  csfDlg.postprocessingcheckbox->setChecked(csf_postprocessing);
123  csfDlg.rig1->setChecked(csf_rigidness == 1);
124  csfDlg.rig2->setChecked(csf_rigidness == 2);
125  csfDlg.rig3->setChecked(csf_rigidness == 3);
126  csfDlg.MaxIterationSpinBox->setValue(MaxIteration);
127  csfDlg.cloth_resolutionSpinBox->setValue(cloth_resolution);
128  csfDlg.class_thresholdSpinBox->setValue(class_threshold);
129  csfDlg.exportClothMeshCheckBox->setChecked(ExportClothMesh);
130 
131  if (!csfDlg.exec()) {
132  return;
133  }
134 
135  // save the parameters for next time
136  csf_postprocessing = csfDlg.postprocessingcheckbox->isChecked();
137  if (csfDlg.rig1->isChecked())
138  csf_rigidness = 1;
139  else if (csfDlg.rig2->isChecked())
140  csf_rigidness = 2;
141  else
142  csf_rigidness = 3;
143  MaxIteration = csfDlg.MaxIterationSpinBox->value();
144  cloth_resolution = csfDlg.cloth_resolutionSpinBox->value();
145  class_threshold = csfDlg.class_thresholdSpinBox->value();
146  ExportClothMesh = csfDlg.exportClothMeshCheckBox->isChecked();
147  }
148 
149  // display the progress dialog
150  QProgressDialog pDlg;
151  pDlg.setWindowTitle("CSF");
152  pDlg.setLabelText(tr("Computing...."));
153  pDlg.setCancelButton(0);
154  pDlg.show();
155  QApplication::processEvents();
156 
157  QElapsedTimer timer;
158  timer.start();
159  // instantiation a CSF class
160  CSF csf(csfPC);
161 
162  // setup parameter
163  csf.params.k_nearest_points = 1;
164  csf.params.bSloopSmooth = csf_postprocessing;
165  csf.params.time_step = 0.65;
168  csf.params.rigidness = csf_rigidness;
170  // to do filtering
171  std::vector<int> groundIndexes, offGroundIndexes;
172  ccMesh* clothMesh = 0;
173  if (!csf.do_filtering(groundIndexes, offGroundIndexes, ExportClothMesh,
174  clothMesh, m_app)) {
175  m_app->dispToConsole(tr("Process failed"),
177  return;
178  }
179 
181  tr("[CSF] %1% of points classified as ground points")
182  .arg((groundIndexes.size() * 100.0) / count, 0, 'f', 2),
185  tr("[CSF] Timing: %1 s.").arg(timer.elapsed() / 1000.0, 0, 'f', 1),
187 
188  // extract ground subset
189  ccPointCloud* groundpoint = 0;
190  {
191  cloudViewer::ReferenceCloud groundpc(pc);
192  if (groundpc.reserve(static_cast<unsigned>(groundIndexes.size()))) {
193  for (unsigned j = 0; j < groundIndexes.size(); ++j) {
194  groundpc.addPointIndex(groundIndexes[j]);
195  }
196  groundpoint = pc->partialClone(&groundpc);
197  }
198  }
199  if (!groundpoint) {
201  tr("Failed to extract the ground subset (not enough memory)"),
203  }
204 
205  // extract off-ground subset
206  ccPointCloud* offgroundpoint = 0;
207  {
208  cloudViewer::ReferenceCloud offgroundpc(pc);
209  if (offgroundpc.reserve(
210  static_cast<unsigned>(offGroundIndexes.size()))) {
211  for (unsigned k = 0; k < offGroundIndexes.size(); ++k) {
212  offgroundpc.addPointIndex(offGroundIndexes[k]);
213  }
214  offgroundpoint = pc->partialClone(&offgroundpc);
215  }
216  }
217  if (!offgroundpoint) {
218  m_app->dispToConsole(tr("Failed to extract the off-ground subset (not "
219  "enough memory)"),
221  if (!groundpoint) {
222  // nothing to do!
223  return;
224  }
225  }
226 
227  pDlg.hide();
228  QApplication::processEvents();
229 
230  // hide the original cloud
231  pc->setEnabled(false);
232 
233  // we add new group to DB/display
234  ccHObject* cloudContainer = new ccHObject(pc->getName() + QString("_csf"));
235  if (groundpoint) {
236  groundpoint->setVisible(true);
237  groundpoint->setName(tr("ground points"));
238  cloudContainer->addChild(groundpoint);
239  }
240 
241  if (offgroundpoint) {
242  offgroundpoint->setVisible(true);
243  offgroundpoint->setName(tr("off-ground points"));
244  cloudContainer->addChild(offgroundpoint);
245  }
246 
247  if (clothMesh) {
248  clothMesh->computePerVertexNormals();
249  clothMesh->showNormals(true);
250  cloudContainer->addChild(clothMesh);
251  }
252 
253  m_app->addToDB(cloudContainer);
254 }
255 
257  if (!cmd) {
258  assert(false);
259  return;
260  }
261  cmd->registerCommand(
263 }
int count
static double cloth_resolution
Definition: ccCSFDlg.cpp:14
static double class_threshold
Definition: ccCSFDlg.cpp:15
static int MaxIteration
Definition: ccCSFDlg.cpp:13
Definition: CSF.h:21
bool do_filtering(std::vector< int > &groundIndexes, std::vector< int > &offGroundIndexes, bool exportClothMesh, ccMesh *&clothMesh, ecvMainAppInterface *app=0, QWidget *parent=0)
Definition: CSF.cpp:73
Parameters params
Definition: CSF.h:63
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
Dialog for qCSF plugin.
Definition: ccCSFDlg.h:13
Command line interface.
virtual bool registerCommand(Command::Shared command)=0
Registers a new command.
virtual QString getName() const override
Returns (short) name (for menu entry, etc.)
virtual QString getDescription() const override
Returns long name/description (for tooltip, etc.)
virtual QIcon getIcon() const override
Returns icon.
virtual void setVisible(bool state)
Sets entity visibility.
void showNormals(bool state) override
Sets normals visibility.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
Triangular mesh.
Definition: ecvMesh.h:35
bool computePerVertexNormals()
Computes per-vertex normals.
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
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.)
ccPointCloud * partialClone(const cloudViewer::ReferenceCloud *selection, int *warnings=nullptr, bool withChildEntities=true) const
Creates a new point cloud object from a ReferenceCloud (selection)
Standard ECV plugin interface.
ecvMainAppInterface * m_app
Main application interface.
unsigned size() const override
Definition: PointCloudTpl.h:38
const CCVector3 * getPoint(unsigned index) const override
A very simple point cloud (no point duplication)
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual bool reserve(unsigned n)
Reserves some memory for hosting the point references.
virtual QMainWindow * getMainWindow()=0
Returns main window.
virtual const ccHObject::Container & getSelectedEntities() const =0
Returns currently selected entities ("read only")
bool haveOneSelection() const
Checks if we have exactly one selection.
virtual void addToDB(ccHObject *obj, bool updateZoom=false, bool autoExpandDBTree=true, bool checkDimensions=false, bool autoRedraw=true)=0
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
void doAction()
Slot called when associated ation is triggered.
Definition: qCSF.cpp:64
QAction * m_action
Associated action.
Definition: qCSF.h:37
virtual QList< QAction * > getActions() override
Get a list of actions for this plugin.
Definition: qCSF.cpp:52
virtual void onNewSelection(const ccHObject::Container &selectedEntities) override
Definition: qCSF.cpp:46
qCSF(QObject *parent=nullptr)
Default constructor.
Definition: qCSF.cpp:41
virtual void registerCommands(ccCommandLineInterface *cmd) override
Optional: registers commands (for the command line mode)
Definition: qCSF.cpp:256
@ POINT_CLOUD
Definition: CVTypes.h:104
double time_step
Definition: CSF.h:52
int iterations
Definition: CSF.h:60
double class_threshold
Definition: CSF.h:54
int k_nearest_points
Definition: CSF.h:48
bool bSloopSmooth
Definition: CSF.h:50
double cloth_resolution
Definition: CSF.h:56
int rigidness
Definition: CSF.h:58
double timer
Definition: struct.h:215
QSharedPointer< Command > Shared
Shared type.
Point type.
Definition: wlPointCloud.h:15