ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ccPointDescriptor.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 "ccPointDescriptor.h"
9 
10 // CV_DB_LIB
11 #include <ecvPointCloud.h>
12 #include <ecvScalarField.h>
13 
14 // cloudViewer
15 #include <Jacobi.h>
16 #include <Neighbourhood.h>
17 
18 // Qt
19 #include <QMap>
20 
21 // system
22 #include <fstream>
23 
24 /**** SCALE PARAMETERS COMPUTERS ****/
25 /* */
26 /* PUT THE CODE OF YOUR OWN BELOW */
27 /* THEN DECLARE IT IN THE "VAULT" */
28 /* (SEE ScaleParamsComputerVault) */
29 /* */
30 /************************************/
31 
32 // useful constant
33 static const double SQRT_3_DIV_2 = sqrt(3.0) / 2;
34 
38 public:
41 
42  // inherited from ScaleParamsComputer
43  virtual unsigned getID() const { return DESC_DIMENSIONALITY; }
44 
45  // inherited from ScaleParamsComputer
46  virtual QString getName() const { return "Dimensionality"; }
47 
48  // inherited from ScaleParamsComputer
49  virtual unsigned dimPerScale() const { return 2; }
50 
51  // inherited from ScaleParamsComputer
52  virtual void reset() {
53  // a = 1/3, b = 1/3
54  // c = 1 - a - b = 1/3
55  // x = b + c/2 = 1/2
56  // y = c * SQRT(3)/2 = SQRT(3)/2 * 1/3
57 
58  m_defaultParams[0] = 0.5;
60 
61  m_firstScale = true;
62  }
63 
64  // inherited from ScaleParamsComputer
66  double radius,
67  float params[],
68  bool& invalidScale) {
69  // PCA analysis
70  if (neighbors.size() >= 3) {
71  cloudViewer::Neighbourhood Z(&neighbors);
72 
73  cloudViewer::SquareMatrixd eigVectors;
74  std::vector<double> eigValues;
76  Z.computeCovarianceMatrix(), eigVectors, eigValues,
77  true)) {
79  eigVectors, eigValues); // decreasing order of their
80  // associated eigenvalues
81 
82  double totalVariance = 0;
83  CCVector3d sValues(0, 0, 0);
84  {
85  // contrarily to Brodu's version, here we get directly the
86  // eigenvalues!
87  for (unsigned j = 0; j < 3; ++j) {
88  sValues.u[j] = eigValues[j];
89  totalVariance += sValues.u[j];
90  }
91  }
92  assert(totalVariance != 0);
93  sValues /= totalVariance;
94 
95  // Use barycentric coordinates : a for 1D, b for 2D and c for 3D
96  // Formula on wikipedia page for barycentric coordinates
97  // using directly the triangle in %variance space, they simplify
98  // a lot
99  double a = std::min<double>(
100  1.0, std::max<double>(0.0, sValues.x - sValues.y));
101  double b = std::min<double>(
102  1.0, std::max<double>(
103  0.0, 2 * sValues.x + 4 * sValues.y - 2.0));
104  double c = 1.0 - a - b;
105  // see original Brodu's code for this transformation
106  params[0] = static_cast<float>(b + c / 2);
107  params[1] = static_cast<float>(c * SQRT_3_DIV_2);
108 
109  // save parameters for next scale
110  m_defaultParams[0] = params[0];
111  m_defaultParams[1] = params[1];
112  m_firstScale = false;
113  } else if (m_firstScale) // PCA failed at first scale?!
114  {
115  invalidScale = true;
116  params[0] = m_defaultParams[0];
117  params[1] = m_defaultParams[1];
118  }
119  } else if (m_firstScale) // less than 3 points at the biggest scale?!
120  {
121  invalidScale = true;
122  params[0] = m_defaultParams[0];
123  params[1] = m_defaultParams[1];
124  }
125 
126  return true;
127  }
128 
129 protected:
131  float m_defaultParams[2];
134 };
135 
136 #ifdef COMPILE_PRIVATE_CANUPO
137 
139 class DimensionalityAndSFScaleParamsComputer : public ScaleParamsComputer {
140 public:
142  DimensionalityAndSFScaleParamsComputer() : m_firstScale(true) {}
143 
144  // inherited from ScaleParamsComputer
145  virtual unsigned getID() const { return DESC_DIMENSIONALITY_SF; }
146 
147  // inherited from ScaleParamsComputer
148  virtual QString getName() const { return "Dimensionality + SF"; }
149 
150  // inherited from ScaleParamsComputer
151  virtual unsigned dimPerScale() const { return 3; }
152 
153  // inherited from ScaleParamsComputer
154  virtual bool needSF() const { return true; }
155 
156  // inherited from ScaleParamsComputer
157  virtual void reset() {
158  // a = 1/3, b = 1/3
159  // c = 1 - a - b = 1/3
160  // x = b + c/2 = 1/2
161  // y = c * SQRT(3)/2 = SQRT(3)/2 * 1/3
162  m_defaultParams[0] = 0.5;
163  m_defaultParams[1] = SQRT_3_DIV_2 / 3;
164 
165  // mean SF value
166  m_defaultParams[2] = 0.0;
167 
168  m_firstScale = true;
169  }
170 
171  // inherited from ScaleParamsComputer
172  virtual bool computeScaleParams(cloudViewer::ReferenceCloud& neighbors,
173  double radius,
174  float params[],
175  bool& invalidScale) {
176  // PCA analysis
177  if (neighbors.size() >= 3) {
178  // first compute the mean SF value
179  unsigned validCount = 0;
180  double meanVal = 0;
181  for (unsigned i = 0; i < neighbors.size(); ++i) {
182  ScalarType val = neighbors.getPointScalarValue(i);
184  meanVal += val;
185  ++validCount;
186  }
187  }
188 
189  if (validCount) {
190  m_defaultParams[2] = static_cast<float>(meanVal / validCount);
191  } else {
192  // not enough (valid) SF values
193  invalidScale = true;
194  params[0] = m_defaultParams[0];
195  params[1] = m_defaultParams[1];
196  params[2] = m_defaultParams[2];
197  return true;
198  }
199 
200  cloudViewer::Neighbourhood Z(&neighbors);
201 
202  cloudViewer::SquareMatrixd eigVectors;
203  std::vector<double> eigValues;
205  Z.computeCovarianceMatrix(), eigVectors, eigValues,
206  true)) {
208  eigVectors, eigValues); // decreasing order of their
209  // associated eigenvalues
210 
211  double totalVariance = 0;
212  CCVector3d sValues(0, 0, 0);
213  {
214  // contrarily to Brodu's version, here we get directly the
215  // eigenvalues!
216  for (unsigned j = 0; j < 3; ++j) {
217  sValues.u[j] = eigValues(j);
218  totalVariance += sValues.u[j];
219  }
220  }
221  assert(totalVariance != 0);
222  sValues /= totalVariance;
223 
224  // Use barycentric coordinates : a for 1D, b for 2D and c for 3D
225  // Formula on wikipedia page for barycentric coordinates
226  // using directly the triangle in %variance space, they simplify
227  // a lot
228  double a = std::min<double>(
229  1.0, std::max<double>(0.0, sValues.x - sValues.y));
230  double b = std::min<double>(
231  1.0, std::max<double>(
232  0.0, 2 * sValues.x + 4 * sValues.y - 2.0));
233  double c = 1.0 - a - b;
234  // see original Brodu's code for this transformation
235  params[0] = static_cast<float>(b + c / 2);
236  params[1] = static_cast<float>(c * SQRT_3_DIV_2);
237 
238  // save parameters for next scale
239  m_defaultParams[0] = params[0];
240  m_defaultParams[1] = params[1];
241  m_defaultParams[2] = params[2];
242  m_firstScale = false;
243  } else if (m_firstScale) // PCA failed at first scale?!
244  {
245  invalidScale = true;
246  params[0] = m_defaultParams[0];
247  params[1] = m_defaultParams[1];
248  params[2] = m_defaultParams[2];
249  }
250  } else if (m_firstScale) // less than 3 points at the biggest scale?!
251  {
252  invalidScale = true;
253  params[0] = m_defaultParams[0];
254  params[1] = m_defaultParams[1];
255  params[2] = m_defaultParams[2];
256  }
257 
258  return true;
259  }
260 
261 protected:
263  float m_defaultParams[3];
265  bool m_firstScale;
266 };
267 
269 class CurvatureScaleParamsComputer : public ScaleParamsComputer {
270 public:
272  CurvatureScaleParamsComputer() : m_firstScale(true) {}
273 
274  // inherited from ScaleParamsComputer
275  virtual unsigned getID() const { return DESC_CURVATURE; }
276 
277  // inherited from ScaleParamsComputer
278  virtual QString getName() const { return "Gaussian curvature"; }
279 
280  // inherited from ScaleParamsComputer
281  virtual unsigned dimPerScale() const { return 1; }
282 
283  // inherited from ScaleParamsComputer
284  virtual void reset() {
285  m_defaultParams[0] = 0;
286  m_firstScale = true;
287  }
288 
289  // inherited from ScaleParamsComputer
290  virtual bool computeScaleParams(cloudViewer::ReferenceCloud& neighbors,
291  double radius,
292  float params[],
293  bool& invalidScale) {
294  // Curvature
295  if (neighbors.size() >= 6) {
296  cloudViewer::Neighbourhood Z(&neighbors);
297  params[0] = Z.computeCurvature(
298  *neighbors.getPoint(0),
300 
301  // save parameters for next scale
302  m_defaultParams[0] = params[0];
303  m_firstScale = false;
304  } else if (m_firstScale) // less than 6 points at the biggest scale?!
305  {
306  invalidScale = true;
307  params[0] = m_defaultParams[0];
308  }
309 
310  return true;
311  }
312 
313 protected:
315  float m_defaultParams[1];
317  bool m_firstScale;
318 };
319 
321 /*class CustomScaleParamsComputer : public ScaleParamsComputer
322 {
323 public:
324 
326  CustomScaleParamsComputer() : m_firstScale(true) {}
327 
328  //inherited from ScaleParamsComputer
329  virtual unsigned getID() const { return DESC_CUSTOM; }
330 
331  //inherited from ScaleParamsComputer
332  virtual QString getName() const { return "Custom"; }
333 
334  //inherited from ScaleParamsComputer
335  virtual unsigned dimPerScale() const { return 1; }
336 
337  //inherited from ScaleParamsComputer
338  virtual void reset()
339  {
340  //FIXME
341  m_defaultParams[0] = 0;
342  m_firstScale = true;
343  }
344 
345  //inherited from ScaleParamsComputer
346  virtual bool computeScaleParams(cloudViewer::ReferenceCloud& neighbors,
347 double radius, float params[], bool& invalidScale)
348  {
349  //Curvature
350  if (neighbors.size() >= ?)
351  {
352  //do something and set the right values for 'params'
353 
354  //save parameters for next scale
355  m_defaultParams[0] = params[0];
356  m_defaultParams[1] = params[1];
357  ...
358  m_firstScale = false;
359  }
360  else if (m_firstScale) //less than 6 points at the biggest
361 scale?!
362  {
363  invalidScale = true;
364  params[0] = m_defaultParams[0];
365  params[1] = m_defaultParams[1];
366  ...
367  }
368 
369  return true;
370  }
371 
372 protected:
373 
375  float m_defaultParams[?];
377  bool m_firstScale;
378 };
379 //*/
380 
381 #endif
382 
383 /**** SCALE PARAMETERS COMPUTERS VAULT ****/
384 /* */
385 /* DON'T FORGET TO ADD YOUR OWN HERE! */
386 /* */
387 /******************************************/
388 
392  // DEFAULT DESCRIPTOR
394 
395 #ifdef COMPILE_PRIVATE_CANUPO
397  new DimensionalityAndSFScaleParamsComputer);
398  map.insert(DESC_CURVATURE, new CurvatureScaleParamsComputer);
399  // ADD YOUR OWN DESCRIPTOR COMPUTERS HERE!
400  // map.insert(DESC_CUSTOM, new CustomScaleParamsComputer);
401  // map.insert(DESC_XXX, new XXXScaleParamsComputer);
402 #endif
403  }
404 
407  // auto delete computers
408  for (QMap<unsigned, ScaleParamsComputer*>::Iterator it = map.begin();
409  it != map.end(); ++it) {
410  delete it.value();
411  it.value() = 0;
412  }
413  map.clear();
414  }
415 
416  QMap<unsigned, ScaleParamsComputer*> map;
417 };
418 
419 /********** OTHER STUFF ***********/
420 /* */
421 /* NO NEED TO LOOK AT THEM ;) */
422 /* */
423 /**********************************/
424 
425 // Unique static instance
427 
429  return static_cast<unsigned>(s_vault.map.size());
430 }
431 
433  if (s_vault.map.contains(descID)) {
434  return s_vault.map[descID];
435  } else {
436  // couldn't find the corresponding descriptor!
437  assert(false);
438  return 0;
439  }
440 }
441 
443  QMap<unsigned, ScaleParamsComputer*>::Iterator it = s_vault.map.begin();
444  for (unsigned i = 0; i < index; ++i) {
445  ++it;
446  assert(it != s_vault.map.end());
447  }
448  return it.value();
449 }
450 
451 QByteArray CorePointDescSet::toByteArray() const {
452  int scaleCount = static_cast<int>(m_scales.size());
453  int descCount = static_cast<int>(size());
454 
455  if (scaleCount == 0 || descCount == 0) return QByteArray();
456 
457  int totalSize = 4 * sizeof(int) /*header*/ +
458  (scaleCount + descCount * scaleCount * m_dimPerScale) *
459  sizeof(float) /*data*/;
460 
461  QByteArray data(totalSize, Qt::Uninitialized);
462 
463  if (data.capacity() < totalSize) // not enough memory?
464  return data;
465 
466  char* buffer = data.data();
467 
468  // header
469  *reinterpret_cast<int*>(buffer) = scaleCount;
470  buffer += sizeof(int);
471  *reinterpret_cast<int*>(buffer) = descCount;
472  buffer += sizeof(int);
473  *reinterpret_cast<int*>(buffer) = static_cast<int>(m_descriptorID);
474  buffer += sizeof(int);
475  *reinterpret_cast<int*>(buffer) = static_cast<int>(m_dimPerScale);
476  buffer += sizeof(int);
477 
478  // scales
479  {
480  for (int i = 0; i < scaleCount; ++i) {
481  *reinterpret_cast<float*>(buffer) = m_scales[i];
482  buffer += sizeof(float);
483  }
484  }
485 
486  // descriptors
487  {
488  for (int j = 0; j < descCount; ++j) {
489  const CorePointDesc& desc = at(j);
490  assert(desc.params.size() == scaleCount * m_dimPerScale);
491  for (size_t i = 0; i < desc.params.size(); ++i) {
492  *reinterpret_cast<float*>(buffer) = desc.params[i];
493  buffer += sizeof(float);
494  }
495  }
496  }
497 
498  // first scales
499  return data;
500 }
501 
502 bool CorePointDescSet::fromByteArray(const QByteArray& data) {
503  if (data.size() < 2 * sizeof(int)) return false;
504 
505  const char* buffer = data.data();
506 
507  // header
508  int scaleCount = *reinterpret_cast<const int*>(buffer);
509  buffer += sizeof(int);
510  int descCount = *reinterpret_cast<const int*>(buffer);
511  buffer += sizeof(int);
512  int descriptorID = *reinterpret_cast<const int*>(buffer);
513  buffer += sizeof(int);
514  if (descriptorID <= 0) return false;
515  m_descriptorID = static_cast<unsigned>(descriptorID);
516  int dimPerScale = *reinterpret_cast<const int*>(buffer);
517  buffer += sizeof(int);
518  if (dimPerScale <= 0) return false;
519  m_dimPerScale = static_cast<unsigned>(dimPerScale);
520 
521  if (scaleCount == 0 || descCount == 0) return false;
522 
523  // check that the array is big enough!
524  int totalSize = 4 * sizeof(int) /*header*/ +
525  (scaleCount + descCount * scaleCount * m_dimPerScale) *
526  sizeof(float) /*data*/;
527  if (data.size() < totalSize) return false;
528 
529  // check that we have enough memory
530  std::vector<float> scales;
531  try {
532  resize(descCount);
533  scales.resize(scaleCount);
534  } catch (const std::bad_alloc&) {
535  // not enough memory
536  return false;
537  }
538 
539  // scales
540  {
541  for (int i = 0; i < scaleCount; ++i) {
542  scales[i] = *reinterpret_cast<const float*>(buffer);
543  buffer += sizeof(float);
544  }
545 
546  // check that we have even more memory ;)
547  if (!setScales(scales)) return false;
548  }
549 
550  // descriptors
551  {
552  for (int j = 0; j < descCount; ++j) {
553  CorePointDesc& desc = at(j);
554  assert(desc.params.size() == scaleCount * m_dimPerScale);
555  for (size_t i = 0; i < scaleCount * m_dimPerScale; ++i) {
556  desc.params[i] = *reinterpret_cast<const float*>(buffer);
557  buffer += sizeof(float);
558  }
559  }
560  }
561 
562  return true;
563 }
564 
565 bool CorePointDescSet::setScales(const std::vector<float>& scales) {
566  assert(size() != 0);
567 
568  // same size as previous scales? Easy...
569  if (scales.size() == m_scales.size()) {
570  m_scales = scales;
571  return true;
572  }
573 
574  // otherwise we must resize the scales vector AND the 'params' structures!
575  try {
576  m_scales = scales;
577  size_t scaleCount = m_scales.size();
578 
579  size_t paramPerDesc = scaleCount * m_dimPerScale;
580  for (size_t i = 0; i < size(); ++i) at(i).params.resize(paramPerDesc);
581  } catch (const std::bad_alloc&) {
582  // not enough memory!
583  return false;
584  }
585  return true;
586 }
587 
589  QString& error,
590  ccPointCloud* corePoints /*=0*/) {
591  error.clear();
592 
593  // DGM: warning, toStdString doesn't preserve "local" characters
594  std::ifstream mscfile(qPrintable(filename), std::ifstream::binary);
595 
596  if (!mscfile.is_open()) {
597  error = "Failed to open input file";
598  return false;
599  }
600 
601  // read the file header
602  int ncorepoints;
603  mscfile.read((char*)&ncorepoints, sizeof(ncorepoints));
604  int nscales_msc;
605  mscfile.read((char*)&nscales_msc, sizeof(int));
606 
607  // default for CANUPO MSC files!
609  m_dimPerScale = 2;
610 
611  // allocate memory
612  {
613  try {
614  resize(ncorepoints);
615  } catch (const std::bad_alloc&) {
616  // not enough memory
617  error = "Not enough memory";
618  return false;
619  }
620 
621  if (corePoints) {
622  // not enough memory to load core points!
623  if (!corePoints->reserve(ncorepoints)) corePoints = 0;
624  }
625  }
626 
627  // read scales
628  {
629  std::vector<float> scales;
630  try {
631  scales.resize(nscales_msc);
632  } catch (const std::bad_alloc&) {
633  // not enough memory
634  error = "Not enough memory";
635  return false;
636  }
637 
638  for (int si = 0; si < nscales_msc; ++si)
639  mscfile.read((char*)&scales[si], sizeof(float));
640 
641  if (!setScales(scales)) // automatically resize the descriptors
642  // 'params' structure
643  {
644  error = "Not enough memory";
645  return false;
646  }
647  }
648 
649  // now load the points and multiscale information from the msc file.
650  // Put the points in the cloud, keep the multiscale information in a
651  // separate vector matched by point index
652  int ptnparams;
653  mscfile.read((char*)&ptnparams, sizeof(int));
654 
655  std::vector<cloudViewer::ScalarField*> paramsSf(3, 0);
656  if (corePoints) {
657  // above 3, ptnparams contains additional scalars
658  for (int i = 3; i < ptnparams; ++i) {
659  int sfIdx = corePoints->addScalarField(
660  qPrintable(QString("scalar #%1").arg(i - 2)));
661  paramsSf.push_back(sfIdx >= 0 ? corePoints->getScalarField(sfIdx)
662  : 0);
663 
664  if (sfIdx < 0) {
665  // just a warning in fact
666  error = "Not enough memory to import additional scalars! (they "
667  "are not used for classification anyway)";
668  }
669  }
670  }
671 
672  // vector<float> avg_ndist_max_scale(ncorepoints);
673  for (int pt = 0; pt < ncorepoints; ++pt) {
674  float x, y, z;
675  mscfile.read((char*)&x, sizeof(float));
676  mscfile.read((char*)&y, sizeof(float));
677  mscfile.read((char*)&z, sizeof(float));
678  if (corePoints) corePoints->addPoint(CCVector3(x, y, z));
679  if (ptnparams >= 4) {
680  float dummy;
681  mscfile.read((char*)&dummy,
682  sizeof(float)); // already ignored in Brodu's code...
683 
684  for (int i = 4; i < ptnparams; ++i) {
685  float param;
686  mscfile.read((char*)&param, sizeof(float));
687 
688  if (static_cast<int>(paramsSf.size()) > i)
689  paramsSf[i]->addElement(static_cast<ScalarType>(param));
690  }
691  }
692 
693  for (int s = 0; s < nscales_msc; ++s) {
694  float a, b;
695  mscfile.read((char*)(&a), sizeof(float));
696  mscfile.read((char*)(&b), sizeof(float));
697 
698  // see original Brodu's code for this transformation
699  float c = 1.0f - a - b;
700  float x = b + c / 2;
701  float y = c * sqrt(3.0f) / 2;
702  at(pt).params[s * 2] = x;
703  at(pt).params[s * 2 + 1] = y;
704  }
705  // we don't care for number of neighbors at max and min scales
706  {
707  int dummyInt;
708  for (int i = 0; i < nscales_msc; ++i)
709  mscfile.read((char*)&dummyInt, sizeof(int));
710  }
711  }
712 
713  mscfile.close();
714 
715  // take care of scalar fields
716  if (corePoints) {
717  bool first = true;
718  for (size_t i = 3; i < paramsSf.size(); ++i) {
719  if (paramsSf[i]) {
720  paramsSf[i]->computeMinAndMax();
721  if (first) {
722  corePoints->setCurrentDisplayedScalarField(
723  corePoints->getScalarFieldIndexByName(
724  paramsSf[i]->getName()));
725  corePoints->showSF(true);
726  first = true;
727  }
728  }
729  }
730  }
731 
732  return true;
733 }
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
std::string filename
int size
cmdLineReadable * params[]
static ScaleParamsComputerVault s_vault
static const double SQRT_3_DIV_2
static const unsigned DESC_DIMENSIONALITY
static const unsigned DESC_CURVATURE
static const unsigned DESC_DIMENSIONALITY_SF
const std::vector< float > & scales() const
Returns associated scales.
const unsigned descriptorID() const
Returns associated descriptor ID.
std::vector< float > m_scales
Associated scales.
unsigned m_descriptorID
Associated descriptor ID.
bool setScales(const std::vector< float > &scales)
Sets associated scales.
const unsigned dimPerScale() const
Returns the number of dimensions per scale.
QByteArray toByteArray() const
Converts structure to a byte array.
bool fromByteArray(const QByteArray &data)
Inits structure from a byte array.
bool loadFromMSC(QString filename, QString &error, ccPointCloud *corePoints=0)
Loads structure of descriptors from an ".msc" file (see Brodu's version)
unsigned m_dimPerScale
Dimensions per scale.
DimensionalityScaleParamsComputer()
Default constructor.
virtual QString getName() const
Returns the associated descriptor name.
virtual void reset()
Called once before computing parameters at first scale.
float m_defaultParams[2]
Default parameters (or last computed scale's ones!)
virtual unsigned dimPerScale() const
Returns the number of dimensions per scale for this descriptor.
virtual unsigned getID() const
Returns the associated descriptor ID.
virtual bool computeScaleParams(cloudViewer::ReferenceCloud &neighbors, double radius, float params[], bool &invalidScale)
Computes the parameters at a given scale.
Jacobi eigen vectors/values decomposition.
Definition: Jacobi.h:23
static bool SortEigenValuesAndVectors(SquareMatrix &eigenVectors, EigenValues &eigenValues)
Definition: Jacobi.h:333
Generic parameters 'computer' class (at a given scale)
static ScaleParamsComputer * GetByID(unsigned descID)
Vault: returns the computer corresponding to the given ID.
virtual unsigned dimPerScale() const =0
Returns the number of dimensions per scale for this descriptor.
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 bool computeScaleParams(cloudViewer::ReferenceCloud &neighbors, double radius, float params[], bool &invalidScale)=0
Computes the parameters at a given scale.
virtual QString getName() const =0
Returns the associated descriptor name.
virtual void reset()=0
Called once before computing parameters at first scale.
virtual bool needSF() const
Returns whether the computer requires a scalar field or not.
Type y
Definition: CVGeom.h:137
Type u[3]
Definition: CVGeom.h:139
Type x
Definition: CVGeom.h:137
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
cloudViewer::SquareMatrixd computeCovarianceMatrix()
Computes the covariance matrix.
A very simple point cloud (no point duplication)
unsigned size() const override
Returns the number of points.
const CCVector3 * getPoint(unsigned index) const override
Returns the ith point.
ScalarType getPointScalarValue(unsigned pointIndex) const override
Returns the ith point associated scalar value.
static bool ValidValue(ScalarType value)
Returns whether a scalar value is valid or not.
Definition: ScalarField.h:61
static void error(char *msg)
Definition: lsd.c:159
Rgb at(size_t color_id)
cloudViewer::GenericIndexedCloud * corePoints
Set of descriptors.
std::vector< float > params
ScaleParamsComputerVault()
Default constructor.
QMap< unsigned, ScaleParamsComputer * > map