ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
AutoSegmentationTools.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
13 #include <ReferenceCloud.h>
14 #include <ScalarField.h>
15 #include <ScalarFieldTools.h>
16 
17 // System
18 #include <algorithm>
19 
20 using namespace cloudViewer;
21 
24  unsigned char level,
25  bool sixConnexity /*=false*/,
26  GenericProgressCallback* progressCb /*=0*/,
27  DgmOctree* inputOctree /*=0*/) {
28  if (!theCloud) {
29  return -1;
30  }
31 
32  // compute octree if none was provided
33  DgmOctree* theOctree = inputOctree;
34  if (!theOctree) {
35  theOctree = new DgmOctree(theCloud);
36  if (theOctree->build(progressCb) < 1) {
37  delete theOctree;
38  return -1;
39  }
40  }
41 
42  // we use the default scalar field to store components labels
43  theCloud->enableScalarField();
44 
45  int result = theOctree->extractCCs(level, sixConnexity, progressCb);
46 
47  // remove octree if it was not provided as input
48  if (theOctree && !inputOctree) {
49  delete theOctree;
50  }
51 
52  return result;
53 }
54 
57  unsigned numberOfPoints = (theCloud ? theCloud->size() : 0);
58  if (numberOfPoints == 0) {
59  return false;
60  }
61 
62  // components should have already been labeled and labels should have been
63  // stored in the active scalar field!
64  if (!theCloud->isScalarFieldEnabled()) {
65  return false;
66  }
67 
68  // empty the input vector if necessary
69  while (!cc.empty()) {
70  delete cc.back();
71  cc.pop_back();
72  }
73 
74  for (unsigned i = 0; i < numberOfPoints; ++i) {
75  ScalarType slabel = theCloud->getPointScalarValue(i);
76  if (slabel >=
77  1) // labels start from 1! (this test rejects NaN values as well)
78  {
79  int ccLabel =
80  static_cast<int>(theCloud->getPointScalarValue(i)) - 1;
81 
82  // we fill the components vector with empty components until we
83  // reach the current label (they will be "used" later)
84  try {
85  while (static_cast<std::size_t>(ccLabel) >= cc.size()) {
86  cc.push_back(new ReferenceCloud(theCloud));
87  }
88  } catch (const std::bad_alloc&) {
89  // not enough memory
90  cc.clear();
91  return false;
92  }
93 
94  // add the point to the current component
95  if (!cc[ccLabel]->addPointIndex(i)) {
96  // not enough memory
97  while (!cc.empty()) {
98  delete cc.back();
99  cc.pop_back();
100  }
101  return false;
102  }
103  }
104  }
105 
106  return true;
107 }
108 
110  GenericIndexedCloudPersist* theCloud,
111  ScalarType minSeedDist,
112  PointCoordinateType radius,
113  unsigned char octreeLevel,
114  ReferenceCloudContainer& theSegmentedLists,
115  GenericProgressCallback* progressCb,
116  DgmOctree* inputOctree,
117  bool applyGaussianFilter,
118  float alpha) {
119  unsigned numberOfPoints = (theCloud ? theCloud->size() : 0);
120  if (numberOfPoints == 0) {
121  return false;
122  }
123 
124  // compute octree if none was provided
125  DgmOctree* theOctree = inputOctree;
126  if (!theOctree) {
127  theOctree = new DgmOctree(theCloud);
128  if (theOctree->build(progressCb) < 1) {
129  delete theOctree;
130  return false;
131  }
132  }
133 
134  // on calcule le gradient (va ecraser le champ des distances)
136  theCloud, radius, true, true, progressCb, theOctree) < 0) {
137  if (!inputOctree) delete theOctree;
138  return false;
139  }
140 
141  // et on lisse le resultat
142  if (applyGaussianFilter) {
144  radius / 3, theCloud, -1, progressCb, theOctree);
145  }
146 
147  unsigned seedPoints = 0;
148  unsigned numberOfSegmentedLists = 0;
149 
150  // on va faire la propagation avec le FastMarching();
152  {
153  fm->setJumpCoef(50.0);
154  fm->setDetectionThreshold(alpha);
155 
156  int result = fm->init(theCloud, theOctree, octreeLevel);
157  if (result < 0) {
158  if (!inputOctree) {
159  delete theOctree;
160  }
161  delete fm;
162  return false;
163  }
164  }
165  int octreeLength = DgmOctree::OCTREE_LENGTH(octreeLevel) - 1;
166 
167  if (progressCb) {
168  if (progressCb->textCanBeEdited()) {
169  progressCb->setMethodTitle("FM Propagation");
170  char buffer[256];
171  sprintf(buffer, "Octree level: %i\nNumber of points: %u",
172  octreeLevel, numberOfPoints);
173  progressCb->setInfo(buffer);
174  }
175  progressCb->update(0);
176  progressCb->start();
177  }
178 
179  ScalarField* theDists = new ScalarField("distances");
180  {
181  ScalarType d = theCloud->getPointScalarValue(0);
182  if (!theDists->resizeSafe(numberOfPoints, true, d)) {
183  if (!inputOctree) delete theOctree;
184  theDists->release();
185  return false;
186  }
187  }
188 
189  unsigned maxDistIndex = 0;
190  unsigned begin = 0;
191  CCVector3 startPoint;
192 
193  while (true) {
194  ScalarType maxDist = NAN_VALUE;
195 
196  // on cherche la premiere distance superieure ou egale a "minSeedDist"
197  while (begin < numberOfPoints) {
198  const CCVector3* thePoint = theCloud->getPoint(begin);
199  const ScalarType& theDistance = theDists->at(begin);
200  ++begin;
201 
202  // FIXME DGM: what happens if SF is negative?!
203  if (theCloud->getPointScalarValue(begin) >= 0 &&
204  theDistance >= minSeedDist) {
205  maxDist = theDistance;
206  startPoint = *thePoint;
207  maxDistIndex = begin;
208  break;
209  }
210  }
211 
212  // il n'y a plus de point avec des distances suffisamment grandes !
213  if (maxDist < minSeedDist) {
214  break;
215  }
216 
217  // on finit la recherche du max
218  for (unsigned i = begin; i < numberOfPoints; ++i) {
219  const CCVector3* thePoint = theCloud->getPoint(i);
220  const ScalarType& theDistance = theDists->at(i);
221 
222  if ((theCloud->getPointScalarValue(i) >= 0.0) &&
223  (theDistance > maxDist)) {
224  maxDist = theDistance;
225  startPoint = *thePoint;
226  maxDistIndex = i;
227  }
228  }
229 
230  // set seed point
231  {
232  Tuple3i cellPos;
233  theOctree->getTheCellPosWhichIncludesThePoint(&startPoint, cellPos,
234  octreeLevel);
235  // clipping (important!)
236  cellPos.x = std::min(octreeLength, cellPos.x);
237  cellPos.y = std::min(octreeLength, cellPos.y);
238  cellPos.z = std::min(octreeLength, cellPos.z);
239  fm->setSeedCell(cellPos);
240  ++seedPoints;
241  }
242 
243  int resultFM = fm->propagate();
244 
245  // if the propagation was successful
246  if (resultFM >= 0) {
247  // we extract the corresponding points
248  ReferenceCloud* newCloud = new ReferenceCloud(theCloud);
249 
250  if (fm->extractPropagatedPoints(newCloud) &&
251  newCloud->size() != 0) {
252  theSegmentedLists.push_back(newCloud);
253  ++numberOfSegmentedLists;
254  } else {
255  // not enough memory?!
256  delete newCloud;
257  newCloud = nullptr;
258  }
259 
260  if (progressCb) {
261  progressCb->update(
262  static_cast<float>(numberOfSegmentedLists % 100));
263  }
264 
265  fm->cleanLastPropagation();
266 
267  // break;
268  }
269 
270  if (maxDistIndex == begin) {
271  ++begin;
272  }
273  }
274 
275  if (progressCb) {
276  progressCb->stop();
277  }
278 
279  for (unsigned i = 0; i < numberOfPoints; ++i) {
280  theCloud->setPointScalarValue(i, theDists->at(i));
281  }
282 
283  theDists->release();
284  theDists = nullptr;
285 
286  if (fm) {
287  delete fm;
288  fm = nullptr;
289  }
290 
291  if (theOctree && !inputOctree) {
292  delete theOctree;
293  theOctree = nullptr;
294  }
295 
296  return true;
297 }
constexpr ScalarType NAN_VALUE
NaN as a ScalarType value.
Definition: CVConst.h:76
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
core::Tensor result
Definition: VtkUtils.cpp:76
virtual void release()
Decrease counter and deletes object when 0.
Definition: CVShareable.cpp:35
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
static int labelConnectedComponents(GenericIndexedCloudPersist *theCloud, unsigned char level, bool sixConnexity=false, cloudViewer::GenericProgressCallback *progressCb=nullptr, cloudViewer::DgmOctree *inputOctree=nullptr)
Labels connected components from a point cloud.
static bool frontPropagationBasedSegmentation(GenericIndexedCloudPersist *theCloud, ScalarType minSeedDist, PointCoordinateType radius, unsigned char octreeLevel, ReferenceCloudContainer &theSegmentedLists, cloudViewer::GenericProgressCallback *progressCb=nullptr, cloudViewer::DgmOctree *inputOctree=nullptr, bool applyGaussianFilter=false, float alpha=2.0f)
static bool extractConnectedComponents(GenericIndexedCloudPersist *theCloud, ReferenceCloudContainer &ccc)
Extracts connected components from a point cloud.
The octree structure used throughout the library.
Definition: DgmOctree.h:39
static int OCTREE_LENGTH(int level)
Definition: DgmOctree.cpp:118
void getTheCellPosWhichIncludesThePoint(const CCVector3 *thePoint, Tuple3i &cellPos) const
Definition: DgmOctree.h:779
int extractCCs(const cellCodesContainer &cellCodes, unsigned char level, bool sixConnexity, GenericProgressCallback *progressCb=nullptr) const
Definition: DgmOctree.cpp:3093
int build(GenericProgressCallback *progressCb=nullptr)
Builds the structure.
Definition: DgmOctree.cpp:196
Fast Marching algorithm for surface front propagation.
void setDetectionThreshold(float value)
Sets the threshold for propagation stop.
int propagate() override
Propagates the front.
void setJumpCoef(float value)
Sets the accceleration exageration factor.
int init(GenericCloud *theCloud, DgmOctree *theOctree, unsigned char gridLevel, bool constantAcceleration=false)
Initializes the grid with a point cloud (and ist corresponding octree)
virtual bool setSeedCell(const Tuple3i &pos)
Sets a given cell as "seed".
virtual void cleanLastPropagation()
virtual bool enableScalarField()=0
Enables the scalar field associated to the cloud.
virtual unsigned size() const =0
Returns the number of points.
virtual ScalarType getPointScalarValue(unsigned pointIndex) const =0
Returns the ith point associated scalar value.
virtual void setPointScalarValue(unsigned pointIndex, ScalarType value)=0
Sets the ith point associated scalar value.
virtual bool isScalarFieldEnabled() const =0
Returns true if the scalar field is enabled, false otherwise.
A generic 3D point cloud with index-based and presistent access to points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
virtual void stop()=0
Notifies the fact that the process has ended.
virtual void setInfo(const char *infoStr)=0
Notifies some information about the ongoing process.
virtual void setMethodTitle(const char *methodTitle)=0
Notifies the algorithm title.
virtual bool textCanBeEdited() const
Returns whether the dialog title and info can be updated or not.
virtual void update(float percent)=0
Notifies the algorithm progress.
A very simple point cloud (no point duplication)
unsigned size() const override
Returns the number of points.
static bool applyScalarFieldGaussianFilter(PointCoordinateType sigma, GenericIndexedCloudPersist *theCloud, PointCoordinateType sigmaSF, GenericProgressCallback *progressCb=nullptr, DgmOctree *theOctree=nullptr)
static int computeScalarFieldGradient(GenericIndexedCloudPersist *theCloud, PointCoordinateType radius, bool euclideanDistances, bool sameInAndOutScalarField=false, GenericProgressCallback *progressCb=nullptr, DgmOctree *theOctree=nullptr)
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
bool resizeSafe(std::size_t count, bool initNewElements=false, ScalarType valueForNewElements=0)
Resizes memory (no exception thrown)
Definition: ScalarField.cpp:81
int min(int a, int b)
Definition: cutil_math.h:53
Generic file read and write utility for python interface.
std::vector< ReferenceCloud * > ReferenceCloudContainer
A standard container to store several subsets of points.
unsigned char octreeLevel