RansacShapeDetector.cpp
Go to the documentation of this file.
1 #ifdef WIN32
2 #include <windows.h>
3 #endif
4 #include "RansacShapeDetector.h"
5 #include <algorithm>
6 #include <functional>
7 #include <ctime>
8 #include <deque>
9 #include <iostream>
10 #include <MiscLib/Random.h>
11 #include "Candidate.h"
12 #include <MiscLib/Performance.h>
13 #include "Octree.h"
16 #ifdef DOPARALLEL
17 #include <omp.h>
18 #endif
19 #undef max
20 #undef min
21 
22 using namespace MiscLib;
23 
25  : m_maxCandTries(20)
26  , m_reqSamples(0)
27  , m_autoAcceptSize(0)
28 {}
29 
31  : m_options(options)
32  , m_maxCandTries(20)
33  , m_reqSamples(0)
34  , m_autoAcceptSize(0)
35 {}
36 
38 {
39  for (ConstructorsType::iterator i = m_constructors.begin(),
40  iend = m_constructors.end(); i != iend; ++i)
41  {
42  (*i)->Release();
43  }
44 }
45 
47 {
48  c->AddRef();
49  m_constructors.push_back(c);
50  if (c->RequiredSamples() > m_reqSamples)
51  {
52  m_reqSamples = c->RequiredSamples();
53  }
54 }
55 
56 size_t RansacShapeDetector::StatBucket(float score) const
57 {
58  return (size_t)std::max(0.f, std::floor((std::log(score) - std::log((float)m_options.m_minSupport)) / std::log(1.21f)) + 1);
59 }
60 
61 /*
62  * Function Detect !!!!
63  */
64 
65 void RansacShapeDetector::UpdateLevelWeights(float factor,
66  const MiscLib::Vector< std::pair< float, size_t > >& levelScores,
67  MiscLib::Vector< double >* sampleLevelProbability) const
68 {
69  MiscLib::Vector< double > newSampleLevelProbability(
70  sampleLevelProbability->size());
71  double newSampleLevelProbabilitySum = 0;
72  for (size_t i = 0; i < newSampleLevelProbability.size(); ++i)
73  {
74  if ((*sampleLevelProbability)[i] > 0)
75  {
76  newSampleLevelProbability[i] = (levelScores[i].first / (*sampleLevelProbability)[i]);
77  }
78  else
79  {
80  newSampleLevelProbability[i] = 0;
81  }
82  newSampleLevelProbabilitySum += newSampleLevelProbability[i];
83  }
84  double newSum = 0;
85  for (size_t i = 0; i < newSampleLevelProbability.size(); ++i)
86  {
87  newSampleLevelProbability[i] = .9f * newSampleLevelProbability[i] + .1f * newSampleLevelProbabilitySum / levelScores.size();
88  newSum += newSampleLevelProbability[i];
89  }
90  for (size_t i = 0; i < sampleLevelProbability->size(); ++i)
91  {
92  (*sampleLevelProbability)[i] = (1.f - factor) * (*sampleLevelProbability)[i] +
93  factor * (newSampleLevelProbability[i] / newSum);
94  }
95 }
96 
97 template< class ScoreVisitorT >
98 void RansacShapeDetector::GenerateCandidates(
99  const IndexedOctreeType& globalOctree,
101  const PointCloud& pc, ScoreVisitorT& scoreVisitor,
102  size_t currentSize, size_t numInvalid,
103  const MiscLib::Vector< double >& sampleLevelProbSum,
104  size_t* drawnCandidates,
105  MiscLib::Vector< std::pair< float, size_t > >* sampleLevelScores,
106  float* bestExpectedValue,
107  CandidatesType* candidates) const
108 {
109  size_t genCands = 0;
110 
111  #pragma omp parallel
112  {
113  ScoreVisitorT scoreVisitorCopy(scoreVisitor);
114  #pragma omp for schedule(dynamic, 10) reduction(+:genCands)
115  for (int candIter = 0; candIter < 200; ++candIter)
116  {
117  // pick a sample level
118  double s = ((double)rand()) / (double)RAND_MAX;
119  size_t sampleLevel = 0;
120  for (; sampleLevel < sampleLevelProbSum.size() - 1; ++sampleLevel)
121  if (sampleLevelProbSum[sampleLevel] >= s)
122  {
123  break;
124  }
125  // draw samples on current sample level in octree
127  const IndexedOctreeType::CellType* node;
128  if (!DrawSamplesStratified(globalOctree, m_reqSamples, sampleLevel,
129  scoreVisitorCopy.GetShapeIndex(), &samples, &node))
130  {
131  continue;
132  }
133  ++genCands;
134  // construct the candidates
135  size_t c = samples.size();
136  MiscLib::Vector< Vec3f > samplePoints(samples.size() << 1);
137  for (size_t i = 0; i < samples.size(); ++i)
138  {
139  samplePoints[i] = globalOctree.at(samples[i]).pos;
140  samplePoints[i + c] = globalOctree.at(samples[i]).normal;
141  }
142  // construct the different primitive shapes
143  PrimitiveShape* shape;
144  for (ConstructorsType::const_iterator i = m_constructors.begin(),
145  iend = m_constructors.end(); i != iend; ++i)
146  {
147  if ((*i)->RequiredSamples() > samples.size()
148  || !(shape = (*i)->Construct(samplePoints)))
149  {
150  continue;
151  }
152  // verify shape
153  std::pair< float, float > dn;
154  bool verified = true;
155  for (size_t i = 0; i < c; ++i)
156  {
157  shape->DistanceAndNormalDeviation(samplePoints[i], samplePoints[i + c], &dn);
158  if (!scoreVisitorCopy.PointCompFunc()(dn.first, dn.second))
159  {
160  verified = false;
161  break;
162  }
163  }
164  if (!verified)
165  {
166  shape->Release();
167  continue;
168  }
169  Candidate cand(shape, node->Level());
170  cand.Indices(new MiscLib::RefCounted< MiscLib::Vector< size_t > >);
171  cand.Indices()->Release();
172  shape->Release();
173  cand.ImproveBounds(octrees, pc, scoreVisitorCopy,
174  currentSize, m_options.m_bitmapEpsilon, 1);
175  if (cand.UpperBound() < m_options.m_minSupport)
176  {
177  #pragma omp critical
178  {
179  (*sampleLevelScores)[node->Level()].first += cand.ExpectedValue();
180  ++(*sampleLevelScores)[node->Level()].second;
181  }
182  continue;
183  }
184 
185  #pragma omp critical
186  {
187  (*sampleLevelScores)[node->Level()].first += cand.ExpectedValue();
188  ++(*sampleLevelScores)[node->Level()].second;
189  candidates->push_back(cand);
190  if (cand.ExpectedValue() > *bestExpectedValue)
191  {
192  *bestExpectedValue = cand.ExpectedValue();
193  }
194  }
195  }
196  }
197  }
198  *drawnCandidates += genCands;
199 }
200 
202 {
203  bool operator()(const Candidate* a, const Candidate* b) const
204  {
205  return *a < *b;
206  }
207 };
208 
209 template< class ScoreVisitorT >
210 bool RansacShapeDetector::FindBestCandidate(CandidatesType& candidates,
212  ScoreVisitorT& scoreVisitor, size_t currentSize,
213  size_t drawnCandidates, size_t numInvalid, size_t minSize, float numLevels,
214  float* maxForgottenCandidate, float* candidateFailProb) const
215 {
216  if (!candidates.size())
217  {
218  return false;
219  }
220  size_t maxImproveSubsetDuringMaxSearch = octrees.size();
221  // sort by expected value
222  std::sort(candidates.begin(), candidates.end());
223  // check if max is smaller than forgotten candidate
224  if (candidates.size() && candidates.back().ExpectedValue() < *maxForgottenCandidate)
225  {
226  // drawn candidates is wrong!
227  // need to correct the value
228  drawnCandidates = std::max(candidates.size(), (size_t)1);
229  *maxForgottenCandidate = 0;
230  }
231 
233  for (size_t i = candidates.size() - 1; i != -1; --i)
234  {
235  if (CandidateFailureProbability(
236  candidates[i].ExpectedValue(),
237  currentSize - numInvalid, drawnCandidates, numLevels) > m_options.m_probability)
238  {
239  break;
240  }
241  candHeap.push_back(&candidates[i]);
242  }
243 
244  if (!candHeap.size())
245  {
246  return false;
247  }
248 
249  std::make_heap(candHeap.begin(), candHeap.end(), CandidateHeapPred());
250 
251  MiscLib::Vector< Candidate* > beatenCands;
252  Candidate* trial = candHeap.front();
253  std::pop_heap(candHeap.begin(), candHeap.end(), CandidateHeapPred());
254  candHeap.pop_back();
255  float bestCandidateFailureProbability;
256  while (candHeap.size())
257  {
258  if (trial->IsEquivalent(*candHeap.front(), pc, m_options.m_epsilon,
259  m_options.m_normalThresh))
260  {
261  std::pop_heap(candHeap.begin(), candHeap.end(),
263  candHeap.pop_back();
264  continue;
265  }
266  bool isEquivalent = false;
267  for (size_t j = 0; j < beatenCands.size(); ++j)
268  {
269  if (beatenCands[j]->IsEquivalent(*candHeap.front(), pc,
270  m_options.m_epsilon, m_options.m_normalThresh))
271  {
272  isEquivalent = true;
273  break;
274  }
275  }
276  if (isEquivalent)
277  {
278  std::pop_heap(candHeap.begin(), candHeap.end(),
280  candHeap.pop_back();
281  continue;
282  }
283  bestCandidateFailureProbability = CandidateFailureProbability(
284  trial->ExpectedValue(),
285  currentSize - numInvalid, drawnCandidates, numLevels);
286  while ((bestCandidateFailureProbability <= m_options.m_probability)
287  && (*trial >= *candHeap.front())
288  && (trial->UpperBound() >= minSize)
289  && trial->ImproveBounds(octrees, pc, scoreVisitor, currentSize,
290  m_options.m_bitmapEpsilon, octrees.size()))
291  {
292  bestCandidateFailureProbability = CandidateFailureProbability(
293  trial->ExpectedValue(),
294  currentSize - numInvalid, drawnCandidates, numLevels);
295  }
296  if (bestCandidateFailureProbability <= m_options.m_probability
297  && trial->UpperBound() >= minSize
298  && trial->ComputedSubsets() >= octrees.size()
299  && *trial >= *candHeap.front())
300  {
301  break;
302  }
303  if (bestCandidateFailureProbability <= m_options.m_probability
304  && trial->UpperBound() >= minSize)
305  {
306  candHeap.push_back(trial);
307  std::push_heap(candHeap.begin(), candHeap.end(), CandidateHeapPred());
308  }
309  else if ((int)trial->ComputedSubsets()
310  > std::max(2, ((int)octrees.size()) - 2))
311  {
312  beatenCands.push_back(trial);
313  }
314  trial = candHeap.front();
315  std::pop_heap(candHeap.begin(), candHeap.end(), CandidateHeapPred());
316  candHeap.pop_back();
317  }
318  bestCandidateFailureProbability = CandidateFailureProbability(
319  trial->ExpectedValue(),
320  currentSize - numInvalid, drawnCandidates, numLevels);
321  while (bestCandidateFailureProbability <= m_options.m_probability
322  && trial->UpperBound() >= minSize
323  && trial->ImproveBounds(octrees, pc, scoreVisitor, currentSize,
324  m_options.m_bitmapEpsilon, octrees.size()))
325  {
326  bestCandidateFailureProbability = CandidateFailureProbability(
327  trial->ExpectedValue(),
328  currentSize - numInvalid, drawnCandidates, numLevels);
329  }
330  if ((bestCandidateFailureProbability > m_options.m_probability
331  || trial->UpperBound() < minSize)
332  && (!m_autoAcceptSize || trial->UpperBound() < m_autoAcceptSize))
333  {
334  return false;
335  }
336  std::sort(candidates.begin(), candidates.end());
337 
338  size_t bestCandidate = candidates.size() - 1;
339  bestCandidateFailureProbability = CandidateFailureProbability(
340  candidates.back().ExpectedValue(),
341  currentSize - numInvalid, drawnCandidates, numLevels);
342 
343  for (size_t i = bestCandidate - 1; i != -1; --i)
344  {
345  float iFailProb = CandidateFailureProbability(candidates[i].ExpectedValue(),
346  currentSize - numInvalid, drawnCandidates, numLevels);
347  if (iFailProb > m_options.m_probability || candidates[i].UpperBound() < minSize
348  || candidates[i].UpperBound() < candidates[bestCandidate].LowerBound())
349  {
350  break;
351  }
352  // check if this is an identical candidate
353  if (candidates[bestCandidate].IsEquivalent(candidates[i], pc,
354  m_options.m_epsilon, m_options.m_normalThresh))
355  {
356  continue;
357  }
358  bool isEquivalent = false;
359  for (size_t j = 0; j < beatenCands.size(); ++j)
360  {
361  if (beatenCands[j]->IsEquivalent(candidates[i], pc,
362  m_options.m_epsilon, m_options.m_normalThresh))
363  {
364  isEquivalent = true;
365  break;
366  }
367  }
368  if (isEquivalent)
369  {
370  continue;
371  }
372  do
373  {
374  if (candidates[i].UpperBound() > candidates[bestCandidate].UpperBound()
375  && candidates[i].LowerBound() < candidates[bestCandidate].LowerBound())
376  {
377  bool dontBreak = candidates[i].ImproveBounds(octrees, pc, scoreVisitor,
378  currentSize, m_options.m_bitmapEpsilon,
379  maxImproveSubsetDuringMaxSearch);
380  iFailProb = CandidateFailureProbability(candidates[i].ExpectedValue(),
381  currentSize - numInvalid, drawnCandidates, numLevels);
382  if (!dontBreak)
383  {
384  break;
385  }
386  }
387  else if (candidates[bestCandidate].UpperBound() > candidates[i].UpperBound()
388  && candidates[bestCandidate].LowerBound() < candidates[i].LowerBound())
389  {
390  bool dontBreak = candidates[bestCandidate].ImproveBounds(octrees, pc,
391  scoreVisitor, currentSize, m_options.m_bitmapEpsilon,
392  maxImproveSubsetDuringMaxSearch);
393  bestCandidateFailureProbability = CandidateFailureProbability(
394  candidates[bestCandidate].ExpectedValue(),
395  currentSize - numInvalid, drawnCandidates, numLevels);
396  if (!dontBreak)
397  {
398  break;
399  }
400  }
401  else
402  {
403  bool dontBreak = candidates[bestCandidate].ImproveBounds(octrees, pc,
404  scoreVisitor, currentSize, m_options.m_bitmapEpsilon,
405  maxImproveSubsetDuringMaxSearch);
406  dontBreak = candidates[i].ImproveBounds(octrees, pc, scoreVisitor,
407  currentSize, m_options.m_bitmapEpsilon,
408  maxImproveSubsetDuringMaxSearch)
409  || dontBreak;
410  iFailProb = CandidateFailureProbability(candidates[i].ExpectedValue(),
411  currentSize - numInvalid, drawnCandidates, numLevels);
412  bestCandidateFailureProbability = CandidateFailureProbability(
413  candidates[bestCandidate].ExpectedValue(),
414  currentSize - numInvalid, drawnCandidates, numLevels);
415  if (!dontBreak)
416  {
417  break;
418  }
419  }
420  }
421  while (bestCandidateFailureProbability <= m_options.m_probability
422  && iFailProb <= m_options.m_probability
423  && candidates[i].UpperBound() >= minSize
424  && candidates[bestCandidate].UpperBound() >= minSize
425  && candidates[i].UpperBound() > candidates[bestCandidate].LowerBound()
426  && candidates[i].LowerBound() < candidates[bestCandidate].UpperBound()
427  );
428  if ((
429  candidates[i] > candidates[bestCandidate]
430  || bestCandidateFailureProbability > m_options.m_probability
431  || candidates[bestCandidate].UpperBound() < minSize)
432  && (iFailProb <= m_options.m_probability && candidates[i].UpperBound() >= minSize))
433  {
434  while (iFailProb <= m_options.m_probability && candidates[i].UpperBound() >= minSize
435  && candidates[i] > candidates[bestCandidate]
436  && candidates[i].ImproveBounds(octrees, pc, scoreVisitor,
437  currentSize, m_options.m_bitmapEpsilon, octrees.size()))
438  {
439  iFailProb = CandidateFailureProbability(candidates[i].ExpectedValue(),
440  currentSize - numInvalid, drawnCandidates, numLevels);
441  }
442  if (candidates[i] > candidates[bestCandidate])
443  {
444  beatenCands.push_back(&candidates[bestCandidate]);
445  bestCandidate = i;
446  bestCandidateFailureProbability = iFailProb;
447  }
448  else
449  {
450  beatenCands.push_back(&candidates[i]);
451  }
452  }
453  else
454  {
455  beatenCands.push_back(&candidates[i]);
456  }
457  if (bestCandidateFailureProbability > m_options.m_probability
458  || candidates[bestCandidate].UpperBound() < minSize)
459  {
460  break;
461  }
462  } // end for
463 
464  while (candidates[bestCandidate].ImproveBounds(octrees, pc, scoreVisitor,
465  currentSize, m_options.m_bitmapEpsilon, octrees.size()));
466 
467  bestCandidateFailureProbability = CandidateFailureProbability(
468  candidates[bestCandidate].ExpectedValue(),
469  currentSize - numInvalid, drawnCandidates, numLevels);
470 
471  if ((bestCandidateFailureProbability <= m_options.m_probability
472  && candidates[bestCandidate].UpperBound() >= minSize)
473  || (m_autoAcceptSize && candidates[bestCandidate].UpperBound() >= m_autoAcceptSize))
474  {
475  std::swap(candidates.back(), candidates[bestCandidate]);
476  *candidateFailProb = bestCandidateFailureProbability;
477  return true;
478  }
479  std::sort(candidates.begin(), candidates.end()/*, std::greater< Candidate >()*/);
480  return false;
481 }
482 
483 size_t
484 RansacShapeDetector::Detect(PointCloud& pc, size_t beginIdx, size_t endIdx,
485  MiscLib::Vector< std::pair< RefCountPtr< PrimitiveShape >, size_t > >* shapes)
486 {
487  const auto endtime = std::chrono::steady_clock::now() + m_options.m_maxruntime;
488  const auto timeout = [&]
489  {
490  return m_options.m_maxruntime.count() != Options::invalidRuntime
491  && endtime <= std::chrono::steady_clock::now();
492  };
493  size_t pcSize = endIdx - beginIdx;
494  /*
495  * Initialization part
496  */
497  srand((unsigned int)time(NULL));
498  rn_setseed((size_t)time(NULL));
499 
500  CandidatesType candidates;
501 
503  ImmediateOctreeType > subsetScoreVisitor(m_options.m_epsilon,
504  m_options.m_normalThresh);
506  IndexedOctreeType > globalScoreVisitor(3 * m_options.m_epsilon,
507  m_options.m_normalThresh);
508 
509  // construct random subsets
510  size_t subsets = std::max(int(std::floor(std::log((float)pcSize) / std::log(2.f))) - 9, 2);
512  bcube.Bound(pc.begin() + beginIdx, pc.begin() + endIdx);
513 
514  // construct stratified subsets
516  for (size_t i = octrees.size(); i;)
517  {
518  --i;
519  size_t subsetSize = pcSize;
520  if (i)
521  {
522  subsetSize = subsetSize >> 1;
523  MiscLib::Vector< size_t > subsetIndices(subsetSize);
524  size_t bucketSize = pcSize / subsetSize;
525  for (size_t j = 0; j < subsetSize; ++j)
526  {
527  size_t index = rn_rand() % bucketSize;
528  index += j * bucketSize;
529  if (index >= pcSize)
530  {
531  index = pcSize - 1;
532  }
533  subsetIndices[j] = index + beginIdx;
534  }
535  // move all the indices to the end
536  std::sort(subsetIndices.begin(), subsetIndices.end(),
537  std::greater< size_t >());
538  for (size_t j = pcSize - 1, i = 0; i < subsetIndices.size(); --j, ++i)
539  {
540  std::swap(pc[j + beginIdx], pc[subsetIndices[i]]);
541  }
542  }
543  octrees[i] = new ImmediateOctreeType;
544  octrees[i]->ContainedData(&pc);
545  octrees[i]->DataRange(pcSize - subsetSize + beginIdx,
546  pcSize + beginIdx);
547  octrees[i]->MaxBucketSize() = 20;
548  octrees[i]->MaxSubdivisionLevel() = 10;
549  octrees[i]->Build(bcube);
550  pcSize -= subsetSize;
551  }
552 
553  pcSize = endIdx - beginIdx;
554 
555  // construct one global octree
556  MiscLib::Vector< size_t > globalOctreeIndices(pcSize);
557  for (size_t i = 0; i < pcSize; ++i)
558  {
559  globalOctreeIndices[i] = i + beginIdx;
560  }
561  IndexedOctreeType globalOctree;
562  globalOctree.MaxBucketSize() = 20;
563  globalOctree.MaxSubdivisionLevel() = 10;
564  globalOctree.IndexedData(globalOctreeIndices.begin(),
565  globalOctreeIndices.end(), pc.begin());
566  globalOctree.Build(bcube);
567  size_t globalOctTreeMaxNodeDepth = globalOctree.MaxDepth();
568 
569  MiscLib::Vector< double > sampleLevelProbability(
570  globalOctTreeMaxNodeDepth + 1);
571  for (size_t i = 0; i < sampleLevelProbability.size(); ++i)
572  {
573  sampleLevelProbability[i] = 1.0 / sampleLevelProbability.size();
574  }
575  size_t drawnCandidates = 0; // keep track of number of candidates
576  // that have been generated
577  float maxForgottenCandidate = 0; // the maximum size of a canidate
578  // that has been forgotten
579  size_t numTries = 0; // number of loops since last successful candidate
580  size_t numShapes = 0; // number of shapes found since the
581  // last housekeeping
582  size_t numInvalid = 0; // number of points that have been assigned
583  // to a shape since the last housekeeping
584  MiscLib::Vector< int > shapeIndex(pc.size(), -1); // maintains for every
585  // point the index of the shape it has been assigned to or
586  // -1 if the point is not assigned yet
587  subsetScoreVisitor.SetShapeIndex(shapeIndex);
588  globalScoreVisitor.SetShapeIndex(shapeIndex);
589  size_t currentSize = pcSize;
590  do
591  {
593  sampleLevelProbability.size());
594  for (size_t i = 0; i < sampleLevelScores.size(); ++i)
595  {
596  sampleLevelScores[i] = std::make_pair(0.f, 0u);
597  }
598  MiscLib::Vector< double >sampleLevelProbSum(sampleLevelProbability.size());
599  sampleLevelProbSum[0] = sampleLevelProbability[0];
600  for (size_t i = 1; i < sampleLevelProbSum.size() - 1; ++i)
601  sampleLevelProbSum[i] = sampleLevelProbability[i] +
602  sampleLevelProbSum[i - 1];
603  sampleLevelProbSum[sampleLevelProbSum.size() - 1] = 1;
604  // generate candidates
605  float bestExpectedValue = 0;
606  if (candidates.size())
607  {
608  bestExpectedValue = candidates.back().ExpectedValue();
609  }
610  bestExpectedValue = std::min((float)(currentSize - numInvalid), bestExpectedValue);
611  do
612  {
613  GenerateCandidates(globalOctree,
614  octrees, pc, subsetScoreVisitor,
615  currentSize, numInvalid,
616  sampleLevelProbSum,
617  &drawnCandidates,
618  &sampleLevelScores,
619  &bestExpectedValue,
620  &candidates);
621  }
622  while (CandidateFailureProbability(bestExpectedValue,
623  currentSize - numInvalid, drawnCandidates,
624  globalOctTreeMaxNodeDepth) > m_options.m_probability
625  && CandidateFailureProbability(m_options.m_minSupport,
626  currentSize - numInvalid, drawnCandidates,
627  globalOctTreeMaxNodeDepth) > m_options.m_probability
628  && !timeout());
629  // find the best candidate:
630  float bestCandidateFailureProbability;
631  float failureProbability = std::numeric_limits< float >::infinity();
632  bool foundCandidate = false;
633  size_t firstCandidateSize = 0;
634  while (FindBestCandidate(candidates, octrees, pc, subsetScoreVisitor,
635  currentSize, drawnCandidates, numInvalid,
636  std::max((size_t)m_options.m_minSupport, (size_t)(0.8f * firstCandidateSize)),
637  globalOctTreeMaxNodeDepth, &maxForgottenCandidate,
638  &bestCandidateFailureProbability))
639  {
640  if (!foundCandidate)
641  {
642  // this is the first candidate
643  firstCandidateSize = (size_t)candidates.back().LowerBound();
644  // rescore levels
645  for (size_t i = 0; i < sampleLevelScores.size(); ++i)
646  {
647  sampleLevelScores[i] = std::make_pair(0.f, 0u);
648  }
649  for (size_t i = 0; i < candidates.size(); ++i)
650  {
651  if (candidates[i].ExpectedValue() * 1.4f > candidates.back().ExpectedValue())
652  {
653  size_t candLevel = std::min(sampleLevelScores.size() - 1,
654  candidates[i].Level());
655  ++sampleLevelScores[candLevel].first;
656  ++sampleLevelScores[candLevel].second;
657  }
658  }
659  UpdateLevelWeights(0.5f, sampleLevelScores, &sampleLevelProbability);
660  }
661  foundCandidate = true;
662  if (bestCandidateFailureProbability < failureProbability)
663  {
664  failureProbability = bestCandidateFailureProbability;
665  }
666  std::string candidateDescription;
667  candidates.back().Shape()->Description(&candidateDescription);
668  // do fitting
669  if (m_options.m_fitting != Options::NO_FITTING)
670  {
671  candidates.back().GlobalScore(globalScoreVisitor, globalOctree);
672  candidates.back().ConnectedComponent(pc, m_options.m_bitmapEpsilon);
673  Candidate clone;
674  candidates.back().Clone(&clone);
675  float oldScore, newScore;
676  size_t oldSize, newSize;
677  // get the weight once
678  newScore = clone.GlobalWeightedScore(globalScoreVisitor, globalOctree,
679  pc, 3 * m_options.m_epsilon, m_options.m_normalThresh,
680  m_options.m_bitmapEpsilon);
681  newSize = std::max(clone.Size(), candidates.back().Size());
682  bool allowDifferentShapes = false;
683  size_t fittingIter = 0;
684  do
685  {
686  ++fittingIter;
687  oldScore = newScore;
688  oldSize = newSize;
689  std::pair< size_t, float > score;
690  PrimitiveShape* shape = Fit(allowDifferentShapes, *clone.Shape(),
691  pc, clone.Indices()->begin(), clone.Indices()->end(),
692  &score);
693  if (shape)
694  {
695  clone.Shape(shape);
696  newScore = clone.GlobalWeightedScore(globalScoreVisitor, globalOctree,
697  pc, 3 * m_options.m_epsilon, m_options.m_normalThresh,
698  m_options.m_bitmapEpsilon);
699  newSize = clone.Size();
700  shape->Release();
701  if (newScore > oldScore && newSize > m_options.m_minSupport)
702  {
703  clone.Clone(&candidates.back());
704  }
705  }
706  allowDifferentShapes = false;
707  }
708  while (newScore > oldScore && fittingIter < 3);
709  }
710  else
711  {
712  candidates.back().GlobalScore(globalScoreVisitor, globalOctree);
713  candidates.back().ConnectedComponent(pc, m_options.m_bitmapEpsilon);
714  }
715  if (candidates.back().Size() == 0)
716  {
717  std::cout << "ERROR: candidate size == 0 after fitting" << std::endl;
718  }
719  // best candidate is ok!
720  // remove the points
721  shapes->push_back(std::make_pair(RefCountPtr< PrimitiveShape >(candidates.back().Shape()),
722  candidates.back().Indices()->size()));
723  for (size_t i = 0; i < candidates.back().Indices()->size(); ++i)
724  {
725  shapeIndex[(*(candidates.back().Indices()))[i]] = numShapes;
726  }
727  ++numShapes;
728  // update drawn candidates to reflect removal of points
729  // get the percentage of candidates that are invalid
730  drawnCandidates = std::pow(1.f - (candidates.back().Indices()->size() /
731  float(currentSize - numInvalid)), 3.f) * drawnCandidates;
732  numInvalid += candidates.back().Indices()->size();
733  candidates.pop_back();
734  if (numInvalid > currentSize / 4) // more than half of the points assigned?
735  {
736  // do a housekeeping step
737  //this is a two stage procedure:
738  // 1) determine the new address of each Point and store it in the shapeIndex array
739  // 2) swap Points according to new addresses
740  size_t begin = beginIdx, end = beginIdx + currentSize;
741 
742  // these hold the address ranges for the lately detected shapes
743  MiscLib::Vector< size_t > shapeIterators(numShapes);
744  int shapeIt = shapes->size() - numShapes;
745  for (size_t i = 0; i < numShapes; ++i, ++shapeIt)
746  {
747  shapeIterators[i] = end -= ((*shapes)[shapeIt]).second;
748  }
749 
750  MiscLib::Vector< size_t > subsetSizes(octrees.size(), 0);
751  for (size_t i = beginIdx, j = 0; i < beginIdx + currentSize; ++i)
752  if (shapeIndex[i] < 0)
753  {
754  if (i >= octrees[j]->end() - pc.begin() + beginIdx
755  && j < octrees.size() - 1)
756  {
757  ++j;
758  }
759  shapeIndex[i] = begin++;
760  ++subsetSizes[j];
761  }
762  else
763  {
764  shapeIndex[i] = shapeIterators[shapeIndex[i]]++;
765  }
766 
767  // check if small subsets should be merged
768  size_t mergedSubsets = 0;
769  if (subsetSizes[0] < 500 && subsetSizes.size() > 1)
770  {
771  // should be merged
772  while (subsetSizes[0] < 500 && subsetSizes.size() > 1)
773  {
774  subsetSizes[1] += subsetSizes[0];
775  subsetSizes.erase(subsetSizes.begin());
776  delete octrees[0];
777  octrees.erase(octrees.begin());
778  ++mergedSubsets;
779  }
780  }
781 
782  // reindex global octree
783  size_t minInvalidIndex = currentSize - numInvalid + beginIdx;
784 #pragma parallel for schedule(static)
785  for (intptr_t i = 0, j = 0; i < globalOctreeIndices.size(); ++i)
786  if (shapeIndex[globalOctreeIndices[i]] < minInvalidIndex)
787  {
788  globalOctreeIndices[j++] = shapeIndex[globalOctreeIndices[i]];
789  }
790  globalOctreeIndices.resize(currentSize - numInvalid);
791 
792  // reindex candidates (this also recomputes the bounds)
793 #pragma parallel for schedule(static)
794  for (intptr_t i = 0; i < candidates.size(); ++i)
795  candidates[i].Reindex(shapeIndex, minInvalidIndex, mergedSubsets,
796  subsetSizes, pc, currentSize - numInvalid, m_options.m_epsilon,
797  m_options.m_normalThresh, m_options.m_bitmapEpsilon);
798 
799  //regarding swapping it is best to swap both the addresses and the data
800  for (size_t i = beginIdx; i < beginIdx + currentSize; ++i)
801  while (i != shapeIndex[i])
802  {
803  pc.swapPoints(i, shapeIndex[i]);
804  std::swap(shapeIndex[i], shapeIndex[shapeIndex[i]]);
805  }
806 
807  numInvalid = 0;
808 
809  // rebuild subset octrees
810  if (mergedSubsets) // the octree for the first subset has to be constructed
811  {
812  //std::cout << "Attention: Merged " << mergedSubsets << " subsets!" << std::endl;
813  MiscLib::Vector< size_t > shuffleIndices(beginIdx + subsetSizes[0]),
814  reindex(beginIdx + subsetSizes[0]);
815  for (size_t i = 0; i < shuffleIndices.size(); ++i)
816  {
817  shuffleIndices[i] = i;
818  }
819  delete octrees[0];
820  octrees[0] = new ImmediateOctreeType();
821  octrees[0]->ContainedData(&pc);
822  octrees[0]->DataRange(beginIdx, beginIdx + subsetSizes[0]);
823  octrees[0]->MaxBucketSize() = 20;
824  octrees[0]->MaxSubdivisionLevel() = 10;
825  octrees[0]->ShuffleIndices(&shuffleIndices);
826  octrees[0]->Build(bcube);
827  octrees[0]->ShuffleIndices(NULL);
828  for (size_t i = 0; i < shuffleIndices.size(); ++i)
829  {
830  reindex[shuffleIndices[i]] = i;
831  }
832  // reindex global octree
833  #pragma omp parallel for schedule(static)
834  for (intptr_t i = 0; i < globalOctreeIndices.size(); ++i)
835  if (globalOctreeIndices[i] < reindex.size())
836  {
837  globalOctreeIndices[i] = reindex[globalOctreeIndices[i]];
838  }
839  // reindex candidates
840  #pragma omp parallel for schedule(static, 100)
841  for (intptr_t i = 0; i < candidates.size(); ++i)
842  {
843  candidates[i].Reindex(reindex);
844  }
845  for (size_t i = 1, begin = subsetSizes[0] + beginIdx;
846  i < octrees.size(); begin += subsetSizes[i], ++i)
847  {
848  octrees[i]->DataRange(begin, begin + subsetSizes[i]);
849  octrees[i]->Rebuild();
850  if (octrees[i]->Root()->Size() != subsetSizes[i])
851  {
852  std::cout << "ERROR IN REBUILD!!!!" << std::endl;
853  }
854  }
855  }
856  else
857  for (size_t i = 0, begin = beginIdx; i < octrees.size();
858  begin += subsetSizes[i], ++i)
859  {
860  octrees[i]->DataRange(begin, begin + subsetSizes[i]);
861  octrees[i]->Rebuild();
862  }
863 
864  //so everything is in its correct place, but we need to update the global octree ranges
865  currentSize = globalOctreeIndices.size();
866 
867  globalOctree.IndexedRange(globalOctreeIndices.begin(),
868  globalOctreeIndices.end());
869  globalOctTreeMaxNodeDepth = globalOctree.Rebuild();
870  if (globalOctree.Root()->Size() != globalOctreeIndices.size())
871  {
872  std::cout << "ERROR IN GLOBAL REBUILD!" << std::endl;
873  }
874  sampleLevelProbability.resize(globalOctTreeMaxNodeDepth + 1);
875 
876  //shapeIndex.resize(globalOctreeIndices.size());
877  std::fill(shapeIndex.begin() + beginIdx,
878  shapeIndex.begin() + beginIdx + currentSize, -1);
879  numShapes = 0;
880  }
881  else
882  {
883  // the bounds of the candidates have become invalid and have to be
884  // recomputed
885 #pragma parallel for schedule(static, 100)
886  for (size_t i = 0; i < candidates.size(); ++i)
887  candidates[i].RecomputeBounds(octrees, pc, subsetScoreVisitor,
888  currentSize - numInvalid, m_options.m_epsilon,
889  m_options.m_normalThresh, m_options.m_bitmapEpsilon);
890  }
891  // remove all candidates that have become obsolete
892  std::sort(candidates.begin(), candidates.end(), std::greater< Candidate >());
893  size_t remainingCandidates = 0;
894  for (size_t i = 0; i < candidates.size(); ++i)
895  if (candidates[i].ExpectedValue() >= m_options.m_minSupport
896  && candidates[i].Size() > 0)
897  {
898  candidates[remainingCandidates++] = candidates[i];
899  }
900  candidates.resize(remainingCandidates);
901  } // Ende abgrasen
902  if (foundCandidate)
903  {
904  std::sort(candidates.begin(), candidates.end(), std::greater< Candidate >());
905  size_t remainingCandidates = 0;
906  size_t nonConnectedCount = 0;
907  for (size_t i = 0; i < candidates.size(); ++i)
908  if (candidates[i].ExpectedValue() >= m_options.m_minSupport &&
909  (candidates[i].ComputedSubsets() > octrees.size() - 3 ||
910  nonConnectedCount++ < 500))
911  {
912  candidates[remainingCandidates++] = candidates[i];
913  }
914  else if (candidates[i].ExpectedValue() > maxForgottenCandidate)
915  {
916  maxForgottenCandidate = candidates[i].ExpectedValue();
917  }
918  candidates.resize(remainingCandidates);
919 
920  numTries = 0;
921  }
922  else
923  {
924  numTries++;
925  }
926  }
927  while (CandidateFailureProbability(m_options.m_minSupport, currentSize - numInvalid,
928  drawnCandidates, globalOctTreeMaxNodeDepth) > m_options.m_probability
929  && (currentSize - numInvalid) >= m_options.m_minSupport
930  && !timeout());
931 
932  if (numInvalid)
933  {
934  // rearrange the last shapes
935  //this is a two stage procedure:
936  // 1) determine the new address of each Point and store it in the shapeIndex array
937  // 2) swap Points according to new addresses
938  size_t begin = beginIdx, end = beginIdx + currentSize;
939  // these hold the address ranges for the lately detected shapes
940  MiscLib::Vector< size_t > shapeIterators(numShapes);
941  int shapeIt = shapes->size() - numShapes;
942  for (size_t i = 0; i < numShapes; ++i, ++shapeIt)
943  {
944  shapeIterators[i] = end -= ((*shapes)[shapeIt]).second;
945  }
946 
947  for (size_t i = beginIdx; i < beginIdx + currentSize; ++i)
948  if (shapeIndex[i] < 0)
949  {
950  shapeIndex[i] = begin++;
951  }
952  else
953  {
954  shapeIndex[i] = shapeIterators[shapeIndex[i]]++;
955  }
956 
957  //regarding swapping it is best to swap both the addresses and the data
958  for (size_t i = beginIdx; i < beginIdx + currentSize; ++i)
959  while (i != shapeIndex[i])
960  {
961  pc.swapPoints(i, shapeIndex[i]);
962  std::swap(shapeIndex[i], shapeIndex[shapeIndex[i]]);
963  }
964  }
965  // clean up subset octrees
966  for (size_t i = 0; i < octrees.size(); ++i)
967  {
968  delete octrees[i];
969  }
970  // optimize parametrizations
971  size_t eidx = endIdx;
972  for (size_t i = 0; i < shapes->size(); ++i)
973  {
974  size_t bidx = eidx - (*shapes)[i].second;
975  (*shapes)[i].first->OptimizeParametrization(pc, bidx, eidx,
976  m_options.m_bitmapEpsilon);
977  eidx = bidx;
978  }
979 
980  // prune nonsense shapes
981  for (size_t i = shapes->size(); i != 0; --i)
982  {
983  if (shapes->at(i - 1).second == 0)
984  {
985  shapes->erase(shapes->begin() + i - 1);
986  }
987  }
988  return currentSize - numInvalid;
989 }
990 
991 bool RansacShapeDetector::DrawSamplesStratified(const IndexedOctreeType& oct,
992  size_t numSamples, size_t depth,
993  const MiscLib::Vector< int >& shapeIndex,
994  MiscLib::Vector< size_t >* samples,
995  const IndexedOctreeType::CellType** node) const
996 {
997  for (size_t tries = 0; tries < m_maxCandTries; tries++)
998  {
999  samples->clear();
1000  //get first point, which also determines octree cell
1001  size_t first;
1002  do
1003  {
1004  first = oct.Dereference(rn_rand() % oct.size());
1005  }
1006  while (shapeIndex[first] != -1);
1007  samples->push_back(first);
1008 
1009  std::pair< size_t, size_t > nodeRange;
1010  *node = oct.NodeContainingPoint(oct.at(first), depth, numSamples,
1011  &nodeRange);
1012 
1013  if ((*node)->Size() < numSamples)
1014  {
1015  continue;
1016  }
1017 
1018  while (samples->size() < numSamples)
1019  {
1020  size_t i, iter = 0;
1021  do
1022  {
1023  i = oct.Dereference(rn_rand() % (*node)->Size()
1024  + nodeRange.first);
1025  }
1026  while ((shapeIndex[i] != -1
1027  || std::find(samples->begin(), samples->end(), i) != samples->end())
1028  && iter++ < 40);
1029  if (iter >= 40)
1030  {
1031  break;
1032  }
1033  samples->push_back(i);
1034  }
1035 
1036  if (samples->size() == numSamples)
1037  {
1038  return true;
1039  }
1040  }
1041  return false;
1042 }
1043 
1044 PrimitiveShape* RansacShapeDetector::Fit(bool allowDifferentShapes,
1045  const PrimitiveShape& initialShape, const PointCloud& pc,
1048  std::pair< size_t, float >* score) const
1049 {
1050  if (!m_constructors.size())
1051  {
1052  return NULL;
1053  }
1054  PrimitiveShape* bestShape = NULL;
1055  if (m_options.m_fitting == Options::LS_FITTING)
1056  bestShape = initialShape.LSFit(pc, m_options.m_epsilon,
1057  m_options.m_normalThresh, begin, end, score);
1058  return bestShape;
1059 }
MiscLib::Vector::front
T & front()
Definition: Vector.h:510
FlatNormalThreshPointCompatibilityFunc.h
GfxTL::AACube
Definition: AACube.h:11
GfxTL::AACubeTree::NodeContainingPoint
const CellType * NodeContainingPoint(const PointT &point, size_t maxLevel, size_t minSize, CellRange *range) const
Definition: AACubeTree.h:399
MiscLib::Vector::begin
T * begin()
Definition: Vector.h:460
MiscLib::RefCounted
Definition: RefCounted.h:10
MiscLib::RefCount::Release
unsigned int Release() const
Definition: RefCount.h:42
MiscLib::NoShrinkVector::pop_back
void pop_back()
Definition: NoShrinkVector.h:379
RansacShapeDetector::Options::invalidRuntime
static constexpr auto invalidRuntime
Definition: RansacShapeDetector.h:24
MiscLib::Vector::push_back
void push_back(const T &v)
Definition: Vector.h:346
Performance.h
index
uint8_t index
Definition: EtherCATFrame.h:59
ScorePrimitiveShapeVisitor.h
RansacShapeDetector.h
Candidate::Clone
void Clone(Candidate *c) const
Definition: Candidate.h:145
MiscLib::Vector::resize
void resize(size_type s, const value_type &v)
Definition: Vector.h:222
RansacShapeDetector::Detect
size_t Detect(PointCloud &pc, size_t begin, size_t end, MiscLib::Vector< std::pair< MiscLib::RefCountPtr< PrimitiveShape >, size_t > > *shapes)
Definition: RansacShapeDetector.cpp:484
Candidate::ImproveBounds
bool ImproveBounds(const MiscLib::Vector< ImmediateOctreeType * > &octrees, const PointCloud &pc, ScoreVisitorT &scoreVisitor, size_t currentSize, float bitmapEpsilon, size_t maxSubset, size_t minPoints=500)
Definition: Candidate.h:188
Candidate::UpperBound
float UpperBound() const
Definition: Candidate.h:35
GfxTL::AACube::Bound
void Bound(const Points &points, size_t size)
Definition: AACube.h:80
MiscLib::Vector::erase
void erase(T *where)
Definition: Vector.h:416
PrimitiveShape
PrimtiveShape is a shape primitive in conjunction with a parametrization.
Definition: PrimitiveShape.h:32
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
RansacShapeDetector::Options::m_bitmapEpsilon
float m_bitmapEpsilon
Definition: RansacShapeDetector.h:37
Candidate::Size
size_t Size() const
Definition: Candidate.h:95
MiscLib::NoShrinkVector::end
T * end()
Definition: NoShrinkVector.h:395
PrimitiveShape::LSFit
virtual PrimitiveShape * LSFit(const PointCloud &pc, float epsilon, float normalThresh, MiscLib::Vector< size_t >::const_iterator begin, MiscLib::Vector< size_t >::const_iterator end, std::pair< size_t, float > *score) const =0
CandidateHeapPred
Definition: RansacShapeDetector.cpp:201
MiscLib::Vector
Definition: Vector.h:19
MiscLib::rn_setseed
void rn_setseed(size_t)
Definition: Random.cpp:25
Candidate::Shape
PrimitiveShape * Shape()
Definition: Candidate.h:23
MiscLib::Vector< PrimitiveShapeConstructor * >::const_iterator
const typedef PrimitiveShapeConstructor * * const_iterator
Definition: Vector.h:26
PrimitiveShapeConstructor
Definition: PrimitiveShapeConstructor.h:22
Candidate
Definition: Candidate.h:18
RansacShapeDetector::Options::m_normalThresh
float m_normalThresh
Definition: RansacShapeDetector.h:35
RansacShapeDetector::RansacShapeDetector
RansacShapeDetector()
Definition: RansacShapeDetector.cpp:24
MiscLib::NoShrinkVector
Definition: NoShrinkVector.h:17
armarx::armem::client::util::swap
void swap(SubscriptionHandle &first, SubscriptionHandle &second)
Definition: SubscriptionHandle.cpp:66
MiscLib::Vector::size
size_type size() const
Definition: Vector.h:212
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
Candidate::ExpectedValue
float ExpectedValue() const
Definition: Candidate.h:51
PrimitiveShape::DistanceAndNormalDeviation
virtual void DistanceAndNormalDeviation(const Vec3f &p, const Vec3f &n, std::pair< float, float > *dn) const =0
MiscLib::rn_rand
size_t rn_rand()
Definition: Random.h:20
MiscLib::Vector::pop_back
void pop_back()
Definition: Vector.h:440
Candidate::ComputedSubsets
size_t ComputedSubsets() const
Definition: Candidate.h:47
Candidate::GlobalWeightedScore
float GlobalWeightedScore(ScoreVisitorT &scoreVisitor, const IndexedOctreeType &oct, const PointCloud &pc, float epsilon, float normalThresh, float bitmapEpsilon)
Definition: Candidate.h:340
RansacShapeDetector::~RansacShapeDetector
virtual ~RansacShapeDetector()
Definition: RansacShapeDetector.cpp:37
RansacShapeDetector::Options
Definition: RansacShapeDetector.h:22
RansacShapeDetector::Options::NO_FITTING
@ NO_FITTING
Definition: RansacShapeDetector.h:38
MiscLib::NoShrinkVector::resize
void resize(size_type s, const value_type &v)
Definition: NoShrinkVector.h:228
MiscLib
Definition: AlignedAllocator.h:11
Candidate::IsEquivalent
bool IsEquivalent(const Candidate &c, const PointCloud &pc, float epsilon, float normalThresh) const
Definition: Candidate.cpp:101
MiscLib::Vector::end
T * end()
Definition: Vector.h:470
max
T max(T t1, T t2)
Definition: gdiam.h:48
RansacShapeDetector::Options::m_fitting
enum RansacShapeDetector::Options::@43 m_fitting
CandidateHeapPred::operator()
bool operator()(const Candidate *a, const Candidate *b) const
Definition: RansacShapeDetector.cpp:203
FlatNormalThreshPointCompatibilityFunc
Definition: FlatNormalThreshPointCompatibilityFunc.h:5
MiscLib::RefCountPtr< PrimitiveShape >
RansacShapeDetector::Options::m_probability
float m_probability
Definition: RansacShapeDetector.h:39
PointCloud
Definition: PointCloud.h:69
RansacShapeDetector::Options::m_minSupport
unsigned int m_minSupport
Definition: RansacShapeDetector.h:36
GfxTL::AACubeTreeCell
Definition: AACubeTree.h:14
RansacShapeDetector::Options::m_maxruntime
std::chrono::milliseconds m_maxruntime
Definition: RansacShapeDetector.h:40
Random.h
RansacShapeDetector::Options::m_epsilon
float m_epsilon
Definition: RansacShapeDetector.h:34
ImmediateOctreeType
GfxTL::AACubeTree< 3, ScoreAACubeTreeStrategy< 3, RebuildAACubeTreeStrategy< GfxTL::BucketSizeMaxLevelSubdivisionTreeStrategy< GfxTL::CellLevelTreeStrategy< GfxTL::CellCenterAACubeTreeStrategy< 3, GfxTL::BaseAACubeTreeStrategy< GfxTL::CellRangeDataTreeStrategy< GfxTL::NullTreeStrategy, GfxTL::ShuffleIndicesTreeDataKernelStrategy< GfxTL::ImmediateRangeTreeDataKernel< PointCloud >, MiscLib::Vector< size_t >>>>>>>>>> ImmediateOctreeType
Definition: Octree.h:49
RansacShapeDetector::Options::LS_FITTING
@ LS_FITTING
Definition: RansacShapeDetector.h:38
MiscLib::NoShrinkVector::begin
T * begin()
Definition: NoShrinkVector.h:385
ScorePrimitiveShapeVisitor
Definition: ScorePrimitiveShapeVisitor.h:89
MiscLib::NoShrinkVector::back
T & back()
Definition: NoShrinkVector.h:425
Octree.h
pc
Introduction Thank you for taking interest in our work and downloading this software This library implements the algorithm described in the paper R R R Klein Efficient RANSAC for Point Cloud Shape in Computer Graphics Blackwell June If you use this software you should cite the aforementioned paper in any resulting publication Please send comments or bug reports to Ruwen Roland BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY OR CONSEQUENTIAL WHETHER IN STRICT OR EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE Example usage This section shows how to use the library to detect the shapes in a point cloud PointCloud pc
Definition: ReadMe.txt:68
MiscLib::NoShrinkVector::size
size_type size() const
Definition: NoShrinkVector.h:218
min
T min(T t1, T t2)
Definition: gdiam.h:42
Candidate.h
shapes
MiscLib::Vector< std::pair< MiscLib::RefCountPtr< PrimitiveShape >, size_t > > shapes
Definition: ReadMe.txt:92
Candidate::Indices
MiscLib::RefCounted< MiscLib::Vector< size_t > > * Indices()
Definition: Candidate.h:39
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
GfxTL::AACubeTree::Build
void Build()
Definition: AACubeTree.h:317
MiscLib::Vector::clear
void clear()
Definition: Vector.h:174
GfxTL::AACubeTree
Definition: AACubeTree.h:287
RansacShapeDetector::Add
void Add(PrimitiveShapeConstructor *c)
Definition: RansacShapeDetector.cpp:46