ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
CSF.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 "CSF.h"
9 
10 #include "Cloth.h"
11 #include "Cloud2CloudDist.h"
12 #include "Rasterization.h"
13 #include "Vec3.h"
14 
15 // CC (for debug)
16 #include <ecvMainAppInterface.h>
17 
18 // Qt
19 #include <QCoreApplication>
20 #include <QElapsedTimer>
21 #include <QProgressDialog>
22 
23 // system
24 #include <cmath>
25 #include <fstream>
26 #include <iomanip>
27 #include <iostream>
28 #include <sstream>
29 
30 CSF::CSF(wl::PointCloud& cloud) : point_cloud(cloud) {
32  params.bSloopSmooth = true;
33  params.time_step = 0.65;
34  params.class_threshold = 0.5;
36  params.rigidness = 3;
37  params.iterations = 500;
38 }
39 
41 
42 bool CSF::readPointsFromFile(std::string filename) {
43  point_cloud.clear();
44 
45  try {
46  std::ifstream fin(filename.c_str(), std::ios::in);
47 
48  char line[500];
49  std::string x, y, z;
50  while (fin.getline(line, sizeof(line))) {
51  std::stringstream words(line);
52  words >> x;
53  words >> y;
54  words >> z;
55  wl::Point P;
56  P.x = static_cast<float>(atof(x.c_str()));
57  P.y = static_cast<float>(-atof(z.c_str()));
58  P.z = static_cast<float>(atof(y.c_str()));
59  point_cloud.push_back(P);
60  }
61  } catch (const std::bad_alloc&) {
62  // not enough memory
63  return false;
64  } catch (...) {
65  // other error
66  return false;
67  }
68 
69  return true;
70 }
71 
72 // CSF主程序 dofiltering
73 bool CSF::do_filtering(std::vector<int>& groundIndexes,
74  std::vector<int>& offGroundIndexes,
75  bool exportClothMesh,
76  ccMesh*& clothMesh,
77  ecvMainAppInterface* app /*=0*/,
78  QWidget* parent /*=0*/) {
79  // constants
80  static const double cloth_y_height = 0.05; // origin cloth height
81  static const int clothbuffer = 2; // set the cloth buffer (grid margin
82  // size)
83  static const double gravity = 0.2;
84 
85  try {
86  QElapsedTimer timer;
87  timer.start();
88 
89  // compute the terrain (cloud) bounding-box
90  wl::Point bbMin, bbMax;
91  point_cloud.computeBoundingBox(bbMin, bbMax);
92 
93  // computing the number of cloth node
94  Vec3 origin_pos(bbMin.x - clothbuffer * params.cloth_resolution,
95  bbMax.y + cloth_y_height,
96  bbMin.z - clothbuffer * params.cloth_resolution);
97 
98  int width_num = static_cast<int>(floor((bbMax.x - bbMin.x) /
100  2 * clothbuffer;
101  int height_num = static_cast<int>(floor((bbMax.z - bbMin.z) /
103  2 * clothbuffer;
104 
105  // Cloth object
106  Cloth cloth(origin_pos, width_num, height_num, params.cloth_resolution,
108  params.time_step);
109  if (app) {
110  app->dispToConsole(QString("[CSF] Cloth creation: %1 ms")
111  .arg(timer.restart()));
112  }
113 
114  if (!Rasterization::RasterTerrain(cloth, point_cloud,
115  cloth.getHeightvals(),
117  return false;
118  }
119  // app->dispToConsole("raster cloth",
120  // ecvMainAppInterface::ERR_CONSOLE_MESSAGE);
121 
122  if (app) {
123  app->dispToConsole(
124  QString("[CSF] Rasterization: %1 ms").arg(timer.restart()));
125  }
126 
127  double time_step2 = params.time_step * params.time_step;
128 
129  // do the filtering
130  QProgressDialog pDlg(parent);
131  pDlg.setWindowTitle("CSF");
132  pDlg.setLabelText(QString("Cloth deformation\n%1 x %2 particles")
133  .arg(cloth.num_particles_width)
134  .arg(cloth.num_particles_height));
135  pDlg.setRange(0, params.iterations);
136  pDlg.show();
137  QCoreApplication::processEvents();
138 
139  bool wasCancelled = false;
140  cloth.addForce(Vec3(0, -gravity, 0) * time_step2);
141  for (int i = 0; i < params.iterations; i++) {
142  // 滤波主过程
143  // cloth.addForce(Vec3(0, -gravity, 0) * time_step2); //move this
144  // outside the main loop
145  double maxDiff = cloth.timeStep();
146  cloth.terrainCollision();
147 
148  // if (app && (i % 50) == 0)
149  //{
150  // app->dispToConsole(QString("[CSF] Iteration %1: max delta =
151  //%2").arg(i+1).arg(maxDiff));
152  // }
153 
154  if (maxDiff != 0 && maxDiff < params.class_threshold / 100) {
155  // early stop
156  break;
157  }
158 
159  pDlg.setValue(i);
160  QCoreApplication::processEvents();
161 
162  if (pDlg.wasCanceled()) {
163  wasCancelled = true;
164  break;
165  }
166  }
167 
168  pDlg.close();
169  QCoreApplication::processEvents();
170 
171  if (app) {
172  app->dispToConsole(
173  QString("[CSF] Iterations: %1 ms").arg(timer.restart()));
174  }
175 
176  if (wasCancelled) {
177  return false;
178  }
179 
180  // slope processing
181  if (params.bSloopSmooth) {
182  cloth.movableFilter();
183 
184  if (app) {
185  app->dispToConsole(QString("[CSF] Movable filter: %1 ms")
186  .arg(timer.restart()));
187  }
188  }
189 
190  // classification of the points
191  bool result = Cloud2CloudDist::Compute(cloth, point_cloud,
193  groundIndexes, offGroundIndexes);
194  if (app) {
195  app->dispToConsole(QString("[CSF] Distance computation: %1 ms")
196  .arg(timer.restart()));
197  }
198 
199  if (exportClothMesh) {
200  clothMesh = cloth.toMesh();
201  }
202 
203  return result;
204  } catch (const std::bad_alloc&) {
205  // not enough memory
206  return false;
207  }
208 }
209 
210 // Exporting the ground points to file.
211 void CSF::saveGroundPoints(const std::vector<int>& grp, std::string path) {
212  std::string filepath = "terr_ground.txt";
213  if (path != "") {
214  filepath = path;
215  }
216  std::ofstream f1(filepath, std::ios::out);
217  if (!f1) return;
218  // clang-format off
219  for (size_t i = 0; i < grp.size(); i++) {
220  f1 << std::fixed << std::setprecision(8) << point_cloud[grp[i]].x << " "
221  << point_cloud[grp[i]].z << " " << -point_cloud[grp[i]].y
222  << std::endl;
223  }
224  // clang-format on
225  f1.close();
226 }
227 
228 void CSF::saveOffGroundPoints(const std::vector<int>& grp, std::string path) {
229  std::string filepath = "off-ground points.txt";
230  if (path != "") {
231  filepath = path;
232  }
233  std::ofstream f1(filepath, std::ios::out);
234  if (!f1) return;
235  // clang-format off
236  for (size_t i = 0; i < grp.size(); i++) {
237  f1 << std::fixed << std::setprecision(8) << point_cloud[grp[i]].x << " "
238  << point_cloud[grp[i]].z << " " << -point_cloud[grp[i]].y
239  << std::endl;
240  }
241  // clang-format on
242  f1.close();
243 }
std::string filename
core::Tensor result
Definition: VtkUtils.cpp:76
void saveGroundPoints(const std::vector< int > &grp, std::string path="")
Definition: CSF.cpp:211
CSF(wl::PointCloud &cloud)
Definition: CSF.cpp:30
virtual ~CSF()
Definition: CSF.cpp:40
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
bool readPointsFromFile(std::string filename)
Definition: CSF.cpp:42
void saveOffGroundPoints(const std::vector< int > &grp, std::string path="")
Definition: CSF.cpp:228
Parameters params
Definition: CSF.h:63
Definition: Cloth.h:44
int num_particles_width
Definition: Cloth.h:88
void movableFilter()
Definition: Cloth.cpp:214
void addForce(const Vec3 &direction)
Definition: Cloth.cpp:187
std::vector< double > & getHeightvals()
Definition: Cloth.h:97
int num_particles_height
Definition: Cloth.h:89
void terrainCollision()
Definition: Cloth.cpp:198
double timeStep()
Definition: Cloth.cpp:146
ccMesh * toMesh() const
Converts the cloth to a CC mesh structure.
Definition: Cloth.cpp:104
static bool Compute(const Cloth &cloth, const wl::PointCloud &pc, double class_threshold, std::vector< int > &groundIndexes, std::vector< int > &offGroundIndexes, unsigned N=3)
static bool RasterTerrain(Cloth &cloth, const wl::PointCloud &pc, std::vector< double > &heightVal, unsigned KNN=1)
Definition: Vec3.h:14
Triangular mesh.
Definition: ecvMesh.h:35
Main application interface (for plugins)
virtual void dispToConsole(QString message, ConsoleMessageLevel level=STD_CONSOLE_MESSAGE)=0
void computeBoundingBox(Point &bbMin, Point &bbMax)
Definition: wlPointCloud.h:30
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
static const std::string path
Definition: PointCloud.cpp:59
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
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
Point type.
Definition: wlPointCloud.h:15