HypothesisGeneration.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package
19  * @author
20  * @date
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 #include "HypothesisGeneration.h"
26 
27 #include "OLPTools.h"
28 #include "SaliencyCalculation.h"
29 
30 // IVT
31 #include "Math/FloatMatrix.h"
32 #include "Math/FloatVector.h"
33 #include "Math/LinearAlgebra.h"
34 #include <Calibration/Calibration.h>
35 #include <Features/SIFTFeatures/SIFTFeatureCalculator.h>
36 #include <Features/SIFTFeatures/SIFTFeatureEntry.h>
37 #include <Image/ByteImage.h>
38 #include <Image/ImageProcessor.h>
39 
40 
41 // OpenMP
42 #include <sys/time.h>
43 
45 
46 #include <omp.h>
47 
49 {
50  ARMARX_INFO_S << "CHypothesisGeneration constructor";
51 
52  // create StereoCalibration
53  this->calibration = calibration;
54 
55  // create SIFTFeatureCalculator
56  m_pSIFTFeatureCalculator = new CSIFTFeatureCalculator();
57 
58  //m_nTimeSum = 0;
59 
60  m_nIterations = 0;
61 
62  m_pSaliencyImage = new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
63  m_pHypothesesCoveringImage =
64  new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
65  m_pSaliencyHypothesisRegionsImage =
66  new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
67  m_pTempImageGray = new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
68 
69 
70 #ifdef OLP_USE_LCCP
71  // LCCPSegmentationWrapper::LCCPSegmentationWrapper(const float voxel_resolution, const float seed_resolution, const float color_importance,
72  // const float spatial_importance, const float normal_importance,, const bool use_single_cam_transform, const float concavity_tolerance_threshold,
73  // const float smoothnessThreshold, const unsigned int min_segment_size, const bool use_extended_convexity, const bool use_sanity_criterion, const float maxZ)
74  lccpSegmentation1 =
75  new LCCPSegmentationWrapper(6, 15.0, 0.0, 1.0, 4.0, false, 10.0, 0.1, 0, false, true, 800);
76  lccpSegmentation2 =
77  new LCCPSegmentationWrapper(15, 26.0, 0.0, 1.0, 4.0, false, 10.0, 0.1, 0, false, true, 800);
78  //lccpSegmentation = new LCCPSegmentationWrapper(7.5, 30.0, 0.0, 1.0, 4.0, false, 10.0, 0.1, 0, false, true);
79 #endif
80  // debug only
81  //fopen_s(&m_pOutFile, "c:/img/points.txt","wt");
82  //fopen_s(&m_pOutFile2, "c:/img/centers.txt","wt");
83  //fopen_s(&m_pOutFile3, "c:/img/center.txt","wt");
84  //m_bTest = true;
85 }
86 
88 {
89  //fclose(m_pOutFile);
90  //fclose(m_pOutFile2);
91  //fclose(m_pOutFile3);
92 
93  delete m_pSIFTFeatureCalculator;
94  delete m_pSaliencyImage;
95  delete m_pHypothesesCoveringImage;
96  delete m_pSaliencyHypothesisRegionsImage;
97  delete m_pTempImageGray;
98 
99 #ifdef OLP_USE_LCCP
100  delete lccpSegmentation1;
101  delete lccpSegmentation2;
102 #endif
103 }
104 
105 void
107  CByteImage* pImageRightColor,
108  CByteImage* pImageLeftGrey,
109  CByteImage* pImageRightGrey,
110  CSIFTFeatureArray& aAllSIFTPoints,
111  std::vector<CMSERDescriptor3D*>& aAllMSERs,
112  std::vector<CHypothesisPoint*>& aPointsFromDisparity,
113  CObjectHypothesisArray& aObjectHypotheses)
114 {
115  ARMARX_INFO_S << "Iteration " << m_nIterations;
116 
117  omp_set_nested(true);
118 
119  timeval tStartAll, tEndAll;
120  timeval tStart, tEnd;
121  long tTimeDiff;
122  gettimeofday(&tStartAll, 0);
123 
124 
125  //**************************************************************************************************************
126  // get all 3D Harris interest points, MSER regions and points from the depth map
127  //**************************************************************************************************************
128 
129  m_vFeaturePoints3d.Clear();
130 
131  // SIFT features at Harris Corner Points
132 
133  for (int i = 0; i < aAllSIFTPoints.GetSize(); i++)
134  {
135  m_vFeaturePoints3d.AddElement(aAllSIFTPoints[i]->point3d);
136  }
137 
138 
139  // MSER regions
140 
141  SortMSERsByX(aAllMSERs);
142 
143  std::vector<Vec3d> aMSERSigmaPoints;
144 
145  // add the central points of the regions to the 3D points
146  for (int i = 0; i < (int)aAllMSERs.size(); i++)
147  {
148  m_vFeaturePoints3d.AddElement(aAllMSERs.at(i)->vPosition);
149 
150  // if the regions are big, also add the sigma points
151 
152  if (aAllMSERs.at(i)->pRegionLeft->fEigenvalue1 > 25.0f) // 36 <=> sqrt(n) pixels
153  {
154  m_vFeaturePoints3d.AddElement(aAllMSERs.at(i)->vSigmaPoint1a);
155  m_vFeaturePoints3d.AddElement(aAllMSERs.at(i)->vSigmaPoint1b);
156  aMSERSigmaPoints.push_back(aAllMSERs.at(i)->vSigmaPoint1a);
157  aMSERSigmaPoints.push_back(aAllMSERs.at(i)->vSigmaPoint1b);
158  }
159 
160  if (aAllMSERs.at(i)->pRegionLeft->fEigenvalue2 > 25.0f)
161  {
162  m_vFeaturePoints3d.AddElement(aAllMSERs.at(i)->vSigmaPoint2a);
163  m_vFeaturePoints3d.AddElement(aAllMSERs.at(i)->vSigmaPoint2b);
164  aMSERSigmaPoints.push_back(aAllMSERs.at(i)->vSigmaPoint2a);
165  aMSERSigmaPoints.push_back(aAllMSERs.at(i)->vSigmaPoint2b);
166  }
167  }
168 
169 
170  ARMARX_VERBOSE_S << m_vFeaturePoints3d.GetSize() << " 3D-points";
171 
172 
173  //**************************************************************************************************************
174  // create hypotheses from large MSERs
175  //**************************************************************************************************************
176 
177  CVec3dArray* paSingleColoredRegions = new CVec3dArray[OLP_MAX_NUM_HYPOTHESES];
178  int nNumSingleColoredRegionHypotheses = 0;
179 
180 #ifdef OLP_FIND_UNICOLORED_HYPOTHESES
181 
182  gettimeofday(&tStart, 0);
183 
184  // get the 2D image coordinates of all depth map points
185  const int nNumPoints = aPointsFromDisparity.size();
186  Vec2d* pDepthMapPoints2D = new Vec2d[nNumPoints];
187 
188  for (int i = 0; i < nNumPoints; i++)
189  {
190  calibration->WorldToImageCoordinates(
191  aPointsFromDisparity.at(i)->vPosition, pDepthMapPoints2D[i], false);
192  }
193 
194  // remove too small or too large MSERs
195  std::vector<CMSERDescriptor3D*> aFilteredMSERs;
196 
197  for (size_t i = 0; i < aAllMSERs.size(); i++)
198  {
199  if (aAllMSERs.at(i)->pRegionLeft->nSize >= OLP_MSER_HYPOTHESIS_MIN_SIZE &&
200  aAllMSERs.at(i)->pRegionLeft->nSize < OLP_MSER_HYPOTHESIS_MAX_SIZE)
201  {
202  aFilteredMSERs.push_back(aAllMSERs.at(i));
203  }
204  }
205 
206  // remove duplicate MSERs
207  SortMSERsBySize(aFilteredMSERs);
208 
209  for (size_t i = 0; i < aFilteredMSERs.size(); i++)
210  {
211  for (size_t j = i + 1; j < aFilteredMSERs.size(); j++)
212  {
213  // if the centers are too close to each other, remove the smaller region
214  if (Math3d::Distance(aFilteredMSERs.at(i)->vPosition, aFilteredMSERs.at(j)->vPosition) <
216  {
217  // overwrite it and move all other entries one index lower
218  for (size_t k = j + 1; k < aFilteredMSERs.size(); k++)
219  {
220  aFilteredMSERs.at(k - 1) = aFilteredMSERs.at(k);
221  }
222 
223  aFilteredMSERs.pop_back();
224  }
225  }
226  }
227 
228  // hypotheses contain all points that lie within the respective MSER
229  const float fPixelDistanceTolerance = 2 * OLP_DEPTH_MAP_PIXEL_DISTANCE;
230  const float fPixelDistanceTolerance2 = fPixelDistanceTolerance * fPixelDistanceTolerance;
231 #pragma omp parallel for schedule(dynamic, 1)
232  for (size_t i = 0; i < aFilteredMSERs.size(); i++)
233  {
234  if (nNumSingleColoredRegionHypotheses >= OLP_MAX_NUM_HYPOTHESES)
235  {
236  continue;
237  }
238 
239  const std::vector<Vec2d>* pRegionPoints = aFilteredMSERs.at(i)->pRegionLeft->pPoints2D;
240 
241  // bounding box of the MSER
242  float minX = pRegionPoints->at(0).x;
243  float minY = pRegionPoints->at(0).y;
244  float maxX = pRegionPoints->at(0).x;
245  float maxY = pRegionPoints->at(0).y;
246 
247  for (size_t k = 1; k < pRegionPoints->size(); k++)
248  {
249  minX = (pRegionPoints->at(k).x < minX) ? pRegionPoints->at(k).x : minX;
250  minY = (pRegionPoints->at(k).y < minY) ? pRegionPoints->at(k).y : minY;
251  maxX = (pRegionPoints->at(k).x > maxX) ? pRegionPoints->at(k).x : maxX;
252  maxY = (pRegionPoints->at(k).y > maxY) ? pRegionPoints->at(k).y : maxY;
253  }
254 
255  minX -= fPixelDistanceTolerance;
256  minY -= fPixelDistanceTolerance;
257  maxX += fPixelDistanceTolerance;
258  maxY += fPixelDistanceTolerance;
259 
260  CVec3dArray pNewColorHypothesisPoints;
261 
262  for (int j = 0; j < nNumPoints; j++)
263  {
264  const float x = pDepthMapPoints2D[j].x;
265  const float y = pDepthMapPoints2D[j].y;
266 
267  if (minX < x && minY < y && x < maxX && y < maxY)
268  {
269  //for (int k = 0; k < aFilteredMSERs.at(i)->pRegionLeft->nSize; k++)
270  for (size_t k = 0; k < pRegionPoints->size(); k++)
271  {
272  if ((x - pRegionPoints->at(k).x) * (x - pRegionPoints->at(k).x) +
273  (y - pRegionPoints->at(k).y) * (y - pRegionPoints->at(k).y) <
274  fPixelDistanceTolerance2)
275  {
276  pNewColorHypothesisPoints.AddElement(aPointsFromDisparity.at(j)->vPosition);
277  break;
278  }
279  }
280  }
281  }
282 
283 #pragma omp critical
284  {
285  if (nNumSingleColoredRegionHypotheses < OLP_MAX_NUM_HYPOTHESES)
286  {
287  if (pNewColorHypothesisPoints.GetSize() > OLP_MIN_NUM_FEATURES)
288  {
289  for (int j = 0; j < pNewColorHypothesisPoints.GetSize(); j++)
290  {
291  paSingleColoredRegions[nNumSingleColoredRegionHypotheses].AddElement(
292  pNewColorHypothesisPoints[j]);
293  }
294 
295  nNumSingleColoredRegionHypotheses++;
296  }
297 
298  pNewColorHypothesisPoints.Clear();
299  }
300  }
301  }
302 
303  gettimeofday(&tEnd, 0);
304  tTimeDiff =
305  (1000 * tEnd.tv_sec + tEnd.tv_usec / 1000) - (1000 * tStart.tv_sec + tStart.tv_usec / 1000);
306 
307  ARMARX_VERBOSE_S << "Number of MSERs: " << aAllMSERs.size() << " total, "
308  << aFilteredMSERs.size() << " unique MSERs. Found "
309  << nNumSingleColoredRegionHypotheses << " unicolored object hypotheses. Took "
310  << tTimeDiff << "ms.";
311 
312 #endif
313 
314 
315  //**************************************************************************************************************
316  // get segments from LCCP segmentation
317  //**************************************************************************************************************
318 
319 #ifdef OLP_USE_LCCP
320 
321  gettimeofday(&tStart, 0);
322  const int maxNumLccpHypotheses = 3000;
323  CVec3dArray* lccpSegmentPoints1 = new CVec3dArray[maxNumLccpHypotheses];
324  CVec3dArray* lccpSegmentPoints2 = new CVec3dArray[maxNumLccpHypotheses];
325  int nNumLCCPSegmentHypotheses1 = 0;
326  int nNumLCCPSegmentHypotheses2 = 0;
327 
328  lccpSegmentation1->CreateHypothesesFromLCCPSegments(
329  aPointsFromDisparity, maxNumLccpHypotheses, lccpSegmentPoints1, nNumLCCPSegmentHypotheses1);
330  lccpSegmentation2->CreateHypothesesFromLCCPSegments(
331  aPointsFromDisparity, maxNumLccpHypotheses, lccpSegmentPoints2, nNumLCCPSegmentHypotheses2);
332 
333  int nNumLCCPSegmentHypotheses = nNumLCCPSegmentHypotheses1 + nNumLCCPSegmentHypotheses2;
334  CVec3dArray* lccpSegmentPoints = new CVec3dArray[nNumLCCPSegmentHypotheses];
335  for (int i = 0; i < nNumLCCPSegmentHypotheses1; i++)
336  {
337  lccpSegmentPoints[i] = lccpSegmentPoints1[i];
338  }
339  for (int i = 0; i < nNumLCCPSegmentHypotheses2; i++)
340  {
341  lccpSegmentPoints[nNumLCCPSegmentHypotheses1 + i] = lccpSegmentPoints2[i];
342  }
343  //delete lccpSegmentPoints1;
344  //delete lccpSegmentPoints2;
345 
346 
347  gettimeofday(&tEnd, 0);
348  tTimeDiff =
349  (1000 * tEnd.tv_sec + tEnd.tv_usec / 1000) - (1000 * tStart.tv_sec + tStart.tv_usec / 1000);
350  ARMARX_VERBOSE_S << "Time for finding LCCP segments: " << tTimeDiff << " ms";
351 
352 #endif
353 
354 
355  //**************************************************************************************************************
356  // search for planes, spheres and cylinders
357  //**************************************************************************************************************
358 
359  gettimeofday(&tStart, 0);
360 
361  CVec3dArray* paPlanes = new CVec3dArray[OLP_MAX_NUM_HYPOTHESES];
362  Vec3d* pPlaneNormals = new Vec3d[OLP_MAX_NUM_HYPOTHESES];
363  float* pPlaneDs = new float[OLP_MAX_NUM_HYPOTHESES];
364  int nNumberOfPlanes = 0;
365  const int nMaxNumberOfClustersPerPlane = OLP_MAX_NUM_CLUSTERING_PARTS;
366  int nNumberOfPlanesAfterClustering = 0;
367  const float fBICFactorPlanes = OLP_CLUSTERING_FACTOR_PLANES; // (bigger -> more clusters)
368  CVec3dArray** pPlanePointsAfterClustering =
369  new CVec3dArray*[nMaxNumberOfClustersPerPlane * OLP_MAX_NUM_HYPOTHESES];
370 
371  CVec3dArray* paCylinders = new CVec3dArray[OLP_MAX_NUM_HYPOTHESES];
372  Vec3d* pCylinderAxes = new Vec3d[OLP_MAX_NUM_HYPOTHESES];
373  Vec3d* pCylinderCenters = new Vec3d[OLP_MAX_NUM_HYPOTHESES];
374  float* pCylinderRadiuses = new float[OLP_MAX_NUM_HYPOTHESES];
375  int nNumberOfCylinders = 0;
376  const int nMaxNumberOfClustersPerCylinder = nMaxNumberOfClustersPerPlane;
377  int nNumberOfCylindersAfterClustering = 0;
378  const float fBICFactorCylinders = fBICFactorPlanes;
379  CVec3dArray** pCylinderPointsAfterClustering =
380  new CVec3dArray*[nMaxNumberOfClustersPerCylinder * OLP_MAX_NUM_HYPOTHESES];
381  Vec3d* pCylinderAxesAfterClustering =
382  new Vec3d[nMaxNumberOfClustersPerCylinder * OLP_MAX_NUM_HYPOTHESES];
383  Vec3d* pCylinderCentersAfterClustering =
384  new Vec3d[nMaxNumberOfClustersPerCylinder * OLP_MAX_NUM_HYPOTHESES];
385  float* pCylinderRadiusesAfterClustering =
386  new float[nMaxNumberOfClustersPerCylinder * OLP_MAX_NUM_HYPOTHESES];
387 
388  CVec3dArray* paSpheres = new CVec3dArray[OLP_MAX_NUM_HYPOTHESES];
389  Vec3d* pSphereCenters = new Vec3d[OLP_MAX_NUM_HYPOTHESES];
390  float* pSphereRadiuses = new float[OLP_MAX_NUM_HYPOTHESES];
391  int nNumberOfSpheres = 0;
392 
393 #ifdef OLP_FIND_PLANES
394  const float fRansacThresholdPlanes = OLP_TOLERANCE_MODIFICATOR * 3.0f; // 2.0
395  const int nRansacIterationsPlanes = (int)(OLP_EFFORT_MODIFICATOR * 500); // 1000
396 #endif
397 #ifdef OLP_FIND_CYLINDERS
398  const float fRansacThresholdCylinders = OLP_TOLERANCE_MODIFICATOR * 5.0f; // 5.0
399  const float fMaxCylinderRadius = 50.0f;
400  bool bFoundCylinder;
401 #endif
402 #ifdef OLP_FIND_SPHERES
403  const float fRansacThresholdSpheres = OLP_TOLERANCE_MODIFICATOR * 5.0f; // 5.0
404  const int nRansacIterationsSpheres = (int)(OLP_EFFORT_MODIFICATOR * 20000); // 30000
405  const float fMaxSphereRadius = 80.0f;
406  bool bFoundSphere;
407 #endif
408 
409  bool bFoundObject = true;
410  bool bFoundPlane;
411  int nNumberOfPointsOnPlane, nNumberOfPointsOnSphere;
412  int nNumberOfPointsOnCylinder = 1000000;
413 
414 
415  for (int i = 0; (i < OLP_MAX_NUM_HYPOTHESES) && bFoundObject &&
416  (m_vFeaturePoints3d.GetSize() > OLP_MIN_NUM_FEATURES);
417  i++)
418  {
419 #ifdef OLP_FIND_PLANES
420  //gettimeofday(&tStart, 0);
421  bFoundPlane = RANSACPlane(m_vFeaturePoints3d,
422  fRansacThresholdPlanes,
423  nRansacIterationsPlanes,
424  paPlanes[nNumberOfPlanes],
425  pPlaneNormals[nNumberOfPlanes],
426  pPlaneDs[nNumberOfPlanes]);
427  nNumberOfPointsOnPlane = bFoundPlane ? paPlanes[nNumberOfPlanes].GetSize() : 0;
428  bFoundPlane &= nNumberOfPointsOnPlane > OLP_MIN_NUM_FEATURES;
429  //gettimeofday(&tEnd, 0);
430  //tTimeDiff = (1000*tEnd.tv_sec+tEnd.tv_usec/1000) - (1000*tStart.tv_sec+tStart.tv_usec/1000);
431  //ARMARX_VERBOSE_S << "time for plane: %ld ms\n", tTimeDiff);
432 #else
433  bFoundPlane = false;
434  nNumberOfPointsOnPlane = 0;
435 #endif
436 
437 #ifdef OLP_FIND_SPHERES
438  bFoundSphere = RANSACSphere(m_vFeaturePoints3d,
439  fRansacThresholdSpheres,
440  fMaxSphereRadius,
441  nRansacIterationsSpheres,
442  paSpheres[nNumberOfSpheres],
443  pSphereCenters[nNumberOfSpheres],
444  pSphereRadiuses[nNumberOfSpheres]);
445 
446  if (bFoundSphere)
447  {
448  nNumberOfPointsOnSphere = (paSpheres[nNumberOfSpheres].GetSize() > OLP_MIN_NUM_FEATURES)
449  ? paSpheres[nNumberOfSpheres].GetSize()
450  : 0;
451  }
452  else
453  {
454  nNumberOfPointsOnSphere = 0;
455  }
456 
457 #else
458  //bFoundSphere = false;
459  nNumberOfPointsOnSphere = 0;
460 #endif
461 
462 #ifdef OLP_FIND_CYLINDERS
463 
464  if ((nNumberOfPointsOnPlane < nNumberOfPointsOnCylinder) &&
465  (nNumberOfPointsOnSphere < nNumberOfPointsOnCylinder))
466  {
467  //gettimeofday(&tStart, 0);
468  bFoundCylinder = RANSACCylinders2(m_vFeaturePoints3d,
469  calibration,
470  fRansacThresholdCylinders,
471  fMaxCylinderRadius,
472  paCylinders[nNumberOfCylinders],
473  pCylinderAxes[nNumberOfCylinders],
474  pCylinderCenters[nNumberOfCylinders],
475  pCylinderRadiuses[nNumberOfCylinders]);
476 
477  if (bFoundCylinder)
478  {
479  nNumberOfPointsOnCylinder =
480  (paCylinders[nNumberOfCylinders].GetSize() > OLP_MIN_NUM_FEATURES)
481  ? paCylinders[nNumberOfCylinders].GetSize()
482  : 0;
483  }
484  else
485  {
486  nNumberOfPointsOnCylinder = 0;
487  }
488 
489  //gettimeofday(&tEnd, 0);
490  //tTimeDiff = (1000*tEnd.tv_sec+tEnd.tv_usec/1000) - (1000*tStart.tv_sec+tStart.tv_usec/1000);
491  //ARMARX_VERBOSE_S << "time for cylinder: %ld ms\n", tTimeDiff);
492  }
493 
494 #else
495  nNumberOfPointsOnCylinder = 0;
496 #endif
497 
498  bFoundObject = true;
499 
500  if ((nNumberOfPointsOnCylinder > nNumberOfPointsOnPlane) &&
501  (nNumberOfPointsOnCylinder > nNumberOfPointsOnSphere))
502  {
503  RemoveOutliers(paCylinders[nNumberOfCylinders], 1.7f, NULL);
504 
505  // find best k-means clustering for the cylinder and divide it if appropriate
506  std::vector<CVec3dArray*> aaPointClusters;
507  ClusterXMeans(paCylinders[nNumberOfCylinders],
508  nMaxNumberOfClustersPerCylinder,
509  fBICFactorCylinders,
510  aaPointClusters);
511  Vec3d vTemp;
512 
513  for (int i = 0; i < (int)aaPointClusters.size(); i++)
514  {
515  RemoveOutliers(*aaPointClusters.at(i), 1.7f, NULL);
516 
517  if (aaPointClusters.at(i)->GetSize() > OLP_MIN_NUM_FEATURES)
518  {
519  if (aaPointClusters.at(i)->GetSize() /
520  GetVariance(*aaPointClusters.at(i), vTemp) >
521  0.004f) // 0.004
522  {
523  pCylinderPointsAfterClustering[nNumberOfCylindersAfterClustering] =
524  aaPointClusters.at(i);
525  pCylinderAxesAfterClustering[nNumberOfCylindersAfterClustering] =
526  pCylinderAxes[nNumberOfCylinders];
527  pCylinderCentersAfterClustering[nNumberOfCylindersAfterClustering] =
528  pCylinderCenters[nNumberOfCylinders];
529  pCylinderRadiusesAfterClustering[nNumberOfCylindersAfterClustering] =
530  pCylinderRadiuses[nNumberOfCylinders];
531 
532  // remove points belonging to the cylinder
533  for (int j = 0;
534  j < pCylinderPointsAfterClustering[nNumberOfCylindersAfterClustering]
535  ->GetSize();
536  j++)
537  {
538  for (int k = 0; k < m_vFeaturePoints3d.GetSize(); k++)
539  {
540  if (m_vFeaturePoints3d[k].x ==
541  (*pCylinderPointsAfterClustering
542  [nNumberOfCylindersAfterClustering])[j]
543  .x &&
544  m_vFeaturePoints3d[k].y ==
545  (*pCylinderPointsAfterClustering
546  [nNumberOfCylindersAfterClustering])[j]
547  .y &&
548  m_vFeaturePoints3d[k].z ==
549  (*pCylinderPointsAfterClustering
550  [nNumberOfCylindersAfterClustering])[j]
551  .z)
552  {
553  const int nEnd = m_vFeaturePoints3d.GetSize() - 1;
554  m_vFeaturePoints3d[k] = m_vFeaturePoints3d[nEnd];
555  m_vFeaturePoints3d.DeleteElement(nEnd);
556  break;
557  }
558  }
559  }
560 
561  nNumberOfCylindersAfterClustering++;
562  }
563  }
564  }
565 
566  aaPointClusters.clear();
567 
568  //ARMARX_VERBOSE_S << "\nFound a cylinder with %d points\nAxis: ( %.2f %.2f %.2f ) Radius: %.1f\n\n", paCylinders[nNumberOfCylinders].GetSize(),
569  // pCylinderAxes[nNumberOfCylinders].x, pCylinderAxes[nNumberOfCylinders].y, pCylinderAxes[nNumberOfCylinders].z, pCylinderRadiuses[nNumberOfCylinders]);
570  nNumberOfCylinders++;
571  }
572  else if (nNumberOfPointsOnSphere > nNumberOfPointsOnPlane)
573  {
574  RemoveOutliers(paSpheres[nNumberOfSpheres], 1.6f, NULL);
575 
576  // remove points belonging to found sphere
577  if (paSpheres[nNumberOfSpheres].GetSize() > OLP_MIN_NUM_FEATURES)
578  {
579  for (int j = 0; j < paSpheres[nNumberOfSpheres].GetSize(); j++)
580  {
581  for (int l = 0; l < m_vFeaturePoints3d.GetSize(); l++)
582  {
583  if (m_vFeaturePoints3d[l].x == paSpheres[nNumberOfSpheres][j].x &&
584  m_vFeaturePoints3d[l].y == paSpheres[nNumberOfSpheres][j].y &&
585  m_vFeaturePoints3d[l].z == paSpheres[nNumberOfSpheres][j].z)
586  {
587  const int nEnd = m_vFeaturePoints3d.GetSize() - 1;
588  m_vFeaturePoints3d[l] = m_vFeaturePoints3d[nEnd];
589  m_vFeaturePoints3d.DeleteElement(nEnd);
590  break;
591  }
592  }
593  }
594 
595  nNumberOfSpheres++;
596  }
597  }
598  else if (bFoundPlane)
599  {
600  RemoveOutliers(paPlanes[nNumberOfPlanes], 1.7f, NULL);
601 
602  // find best k-means clustering for the plane and divide it if appropriate
603  std::vector<CVec3dArray*> aaPointClusters;
604  ClusterXMeans(paPlanes[nNumberOfPlanes],
605  nMaxNumberOfClustersPerPlane,
606  fBICFactorPlanes,
607  aaPointClusters);
608  Vec3d vTemp;
609 
610  for (int i = 0; i < (int)aaPointClusters.size(); i++)
611  {
612  RemoveOutliers(*aaPointClusters.at(i), 1.7f, NULL);
613  RemoveOutliers(*aaPointClusters.at(i), 2.0f, NULL);
614 
615  if (aaPointClusters.at(i)->GetSize() > OLP_MIN_NUM_FEATURES)
616  {
617  if (aaPointClusters.at(i)->GetSize() /
618  GetVariance(*aaPointClusters.at(i), vTemp) >
619  0.004f) // 0.004
620  {
621  pPlanePointsAfterClustering[nNumberOfPlanesAfterClustering] =
622  aaPointClusters.at(i);
623 
624  // remove points belonging to the plane
625  for (int j = 0;
626  j <
627  pPlanePointsAfterClustering[nNumberOfPlanesAfterClustering]->GetSize();
628  j++)
629  {
630  for (int k = 0; k < m_vFeaturePoints3d.GetSize(); k++)
631  {
632  if (m_vFeaturePoints3d[k].x ==
633  (*pPlanePointsAfterClustering
634  [nNumberOfPlanesAfterClustering])[j]
635  .x &&
636  m_vFeaturePoints3d[k].y ==
637  (*pPlanePointsAfterClustering
638  [nNumberOfPlanesAfterClustering])[j]
639  .y &&
640  m_vFeaturePoints3d[k].z ==
641  (*pPlanePointsAfterClustering
642  [nNumberOfPlanesAfterClustering])[j]
643  .z)
644  {
645  const int nEnd = m_vFeaturePoints3d.GetSize() - 1;
646  m_vFeaturePoints3d[k] = m_vFeaturePoints3d[nEnd];
647  m_vFeaturePoints3d.DeleteElement(nEnd);
648  break;
649  }
650  }
651  }
652 
653  nNumberOfPlanesAfterClustering++;
654  }
655  }
656  }
657 
658  aaPointClusters.clear();
659 
660  //ARMARX_VERBOSE_S << "\nFound a plane with %d points\nNormal: ( %.2f %.2f %.2f )\n\n", paPlanes[nNumberOfPlanes].GetSize(),
661  // pPlaneNormals[nNumberOfPlanes].x, pPlaneNormals[nNumberOfPlanes].y, pPlaneNormals[nNumberOfPlanes].z);
662  nNumberOfPlanes++;
663  }
664  else
665  {
666  bFoundObject = false;
667  }
668  }
669 
670 
671  ARMARX_VERBOSE_S << "Found " << nNumberOfCylinders << " cylinders and " << nNumberOfPlanes
672  << " planes (" << nNumberOfPlanesAfterClustering
673  << " planes after clustering)";
674 
675  gettimeofday(&tEnd, 0);
676  tTimeDiff =
677  (1000 * tEnd.tv_sec + tEnd.tv_usec / 1000) - (1000 * tStart.tv_sec + tStart.tv_usec / 1000);
678  ARMARX_VERBOSE_S << "Time for finding planes, cylinders and spheres: " << tTimeDiff << " ms";
679 
680  //m_nTimeSum += tTimeDiff;
681  //ARMARX_VERBOSE_S << "Avg. time for finding objects: " << m_nTimeSum/(m_nIterations+1) << " ms";
682 
683 
684  //**************************************************************************************************************
685  // try to find clusters amongst the leftover points
686  //**************************************************************************************************************
687 
688  gettimeofday(&tStart, 0);
689 
690 
691  int nNumberOfUnstructuredClusters = 0;
692  CVec3dArray** pUnstructuredPointClusters = NULL;
693 #ifdef OLP_FIND_IRREGULAR_CLUSTERS
694  std::vector<CVec3dArray*> aaUnstructuredPointClusters;
695  const int nMaxNumberOfUnstructuredClusters = 15 + (int)(2 * sqrtf(OLP_EFFORT_MODIFICATOR));
696  const float fBICFactorLeftoverPoints = 4.0f * OLP_CLUSTERING_FACTOR_PLANES;
697  //cv::Mat mSamples;
698  //cv::Mat mClusterLabels;
699  //cv::Mat* pmClusterCenters = NULL;
700  //const int nNumberOfDifferentInitialisations = 5;
701  //cv::TermCriteria tTerminationCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 50, 0.01);
702  pUnstructuredPointClusters = new CVec3dArray*[nMaxNumberOfUnstructuredClusters];
703 
704  // remove points that lie far off
705  RemoveOutliers(m_vFeaturePoints3d, 2.0f);
706 
707  // find best k-means clustering for the points
708  ClusterXMeans(m_vFeaturePoints3d,
709  nMaxNumberOfUnstructuredClusters,
710  fBICFactorLeftoverPoints,
711  aaUnstructuredPointClusters);
712  Vec3d vTemp;
713 
714  // check if the clusters form plausible hypotheses
715  for (int i = 0; i < (int)aaUnstructuredPointClusters.size(); i++)
716  {
717  RemoveOutliers(*aaUnstructuredPointClusters.at(i), 1.5f, NULL);
718  RemoveOutliers(*aaUnstructuredPointClusters.at(i), 2.0f, NULL);
719 
720  if (aaUnstructuredPointClusters.at(i)->GetSize() > OLP_MIN_NUM_FEATURES)
721  {
722  if (aaUnstructuredPointClusters.at(i)->GetSize() /
723  GetVariance(*aaUnstructuredPointClusters.at(i), vTemp) >
724  0.004f) // 0.003
725  {
726  pUnstructuredPointClusters[nNumberOfUnstructuredClusters] =
727  aaUnstructuredPointClusters.at(i);
728 
729  // remove points belonging to the plane
730  for (int j = 0;
731  j < pUnstructuredPointClusters[nNumberOfUnstructuredClusters]->GetSize();
732  j++)
733  {
734  for (int k = 0; k < m_vFeaturePoints3d.GetSize(); k++)
735  {
736  if (m_vFeaturePoints3d[k].x ==
737  (*pUnstructuredPointClusters[nNumberOfUnstructuredClusters])[j].x &&
738  m_vFeaturePoints3d[k].y ==
739  (*pUnstructuredPointClusters[nNumberOfUnstructuredClusters])[j].y &&
740  m_vFeaturePoints3d[k].z ==
741  (*pUnstructuredPointClusters[nNumberOfUnstructuredClusters])[j].z)
742  {
743  const int nEnd = m_vFeaturePoints3d.GetSize() - 1;
744  m_vFeaturePoints3d[k] = m_vFeaturePoints3d[nEnd];
745  m_vFeaturePoints3d.DeleteElement(nEnd);
746  break;
747  }
748  }
749  }
750 
751  nNumberOfUnstructuredClusters++;
752  }
753  }
754  }
755 
756  aaUnstructuredPointClusters.clear();
757 #endif
758 
759 
760  //ARMARX_VERBOSE_S << "Found %d clusters amongst the leftover features\n", nNumberOfUnstructuredClusters);
761 
762  //gettimeofday(&tEnd, 0);
763  //tTimeDiff = (1000*tEnd.tv_sec+tEnd.tv_usec/1000) - (1000*tStart.tv_sec+tStart.tv_usec/1000);
764  //ARMARX_VERBOSE_S << "Time for clustering of leftover features: %ld ms\n", tTimeDiff);
765 
766 
767  //**************************************************************************************************************
768  // generate hypothesis descriptors
769  //**************************************************************************************************************
770 
771 
772  // add the plane, cylinder and sphere hypotheses, sorted by the number of points that they contain
773 
774  CObjectHypothesis* pHypothesis;
775 
776  // add the planes to the hypothesis list
777  for (int i = 0; i < nNumberOfPlanesAfterClustering; i++)
778  {
779  pHypothesis = CreatePlaneHypothesisDescriptor(*pPlanePointsAfterClustering[i],
780  aAllMSERs,
781  aMSERSigmaPoints,
782  pImageLeftColor,
783  pImageLeftGrey);
784  aObjectHypotheses.AddElement(pHypothesis);
785  }
786 
787  // add the cylinders to the hypothesis list
788  for (int i = 0; i < nNumberOfCylindersAfterClustering; i++)
789  {
790  pHypothesis = CreateCylinderHypothesisDescriptor(*pCylinderPointsAfterClustering[i],
791  pCylinderAxesAfterClustering[i],
792  pCylinderCentersAfterClustering[i],
793  pCylinderRadiusesAfterClustering[i],
794  aAllMSERs,
795  aMSERSigmaPoints,
796  pImageLeftColor,
797  pImageLeftGrey);
798  aObjectHypotheses.AddElement(pHypothesis);
799  }
800 
801 
802  // add the spheres to the hypothesis list
803  for (int i = 0; i < nNumberOfSpheres; i++)
804  {
805  pHypothesis = CreateSphereHypothesisDescriptor(paSpheres[i],
806  pSphereCenters[i],
807  pSphereRadiuses[i],
808  aAllMSERs,
809  aMSERSigmaPoints,
810  pImageLeftColor,
811  pImageLeftGrey);
812  aObjectHypotheses.AddElement(pHypothesis);
813  }
814 
815 
816  // add the unstructured clusters
817  for (int i = 0; i < nNumberOfUnstructuredClusters; i++)
818  {
819  pHypothesis = CreatePlaneHypothesisDescriptor(*pUnstructuredPointClusters[i],
820  aAllMSERs,
821  aMSERSigmaPoints,
822  pImageLeftColor,
823  pImageLeftGrey);
825  aObjectHypotheses.AddElement(pHypothesis);
826  }
827 
828  // add the hypotheses from unicolored regions
829  for (int i = 0; i < nNumSingleColoredRegionHypotheses; i++)
830  {
831  pHypothesis = CreatePlaneHypothesisDescriptor(paSingleColoredRegions[i],
832  aAllMSERs,
833  aMSERSigmaPoints,
834  pImageLeftColor,
835  pImageLeftGrey);
837  aObjectHypotheses.AddElement(pHypothesis);
838  }
839 
840 #ifdef OLP_USE_LCCP
841 
842  ARMARX_VERBOSE_S << "Adding " << nNumLCCPSegmentHypotheses << " hypotheses from LCCP";
843  int counter = 0;
844  for (int i = 0; i < nNumLCCPSegmentHypotheses; i++)
845  {
846  if ((lccpSegmentPoints[i].GetSize() > OLP_MIN_SIZE_LCCP_SEGMENT) &&
847  (lccpSegmentPoints[i].GetSize() < OLP_MAX_SIZE_LCCP_SEGMENT))
848  {
849  pHypothesis = CreatePlaneHypothesisDescriptor(
850  lccpSegmentPoints[i], aAllMSERs, aMSERSigmaPoints, pImageLeftColor, pImageLeftGrey);
851  pHypothesis->eType = CObjectHypothesis::eRGBD;
852  aObjectHypotheses.AddElement(pHypothesis);
853 
854 #ifdef OLP_MAKE_LCCP_SEG_IMAGES
855  CByteImage* segmentationImage =
856  new CByteImage(OLP_IMG_WIDTH, OLP_IMG_HEIGHT, CByteImage::eGrayScale);
858  pHypothesis, calibration, segmentationImage);
859 
860  std::string fileName = OLP_SCREENSHOT_PATH;
861  fileName.append("lccp0000.bmp");
862  int fileNumber = m_nIterations * 1000 + counter;
863  COLPTools::SetNumberInFileName(fileName, fileNumber);
864  counter++;
865  ARMARX_VERBOSE_S << "Saving LCCP segmentation image for segment " << i << ": "
866  << fileName;
867  segmentationImage->SaveToFile(fileName.c_str());
868  delete segmentationImage;
869 #endif
870  }
871  }
872 
873 #endif
874 
875 
876  //**************************************************************************************************************
877  // generate hypotheses in the not-yet-covered salient regions
878  //**************************************************************************************************************
879 
880 #ifdef OLP_FIND_SALIENCY_HYPOTHESES
881 
882  gettimeofday(&tStart, 0);
883 
884  // calculate saliency map
885  CSaliencyCalculation::FindSalientRegionsAchanta(pImageLeftColor, m_pSaliencyImage);
886 
887  // calculate area already covered by other hypotheses
888  ImageProcessor::Zero(m_pHypothesesCoveringImage);
889 
890  for (int i = 0; i < aObjectHypotheses.GetSize(); i++)
891  {
893  aObjectHypotheses[i], calibration, m_pTempImageGray);
894  ImageProcessor::Or(
895  m_pHypothesesCoveringImage, m_pTempImageGray, m_pHypothesesCoveringImage);
896  }
897 
898  ImageProcessor::Dilate(m_pHypothesesCoveringImage, m_pTempImageGray);
899  ImageProcessor::Dilate(m_pTempImageGray, m_pHypothesesCoveringImage);
900  ImageProcessor::Dilate(m_pHypothesesCoveringImage, m_pTempImageGray);
901  ImageProcessor::Dilate(m_pTempImageGray, m_pHypothesesCoveringImage);
902  ImageProcessor::Dilate(m_pHypothesesCoveringImage, m_pTempImageGray);
903  ImageProcessor::Erode(m_pTempImageGray, m_pHypothesesCoveringImage);
904  ImageProcessor::Erode(m_pHypothesesCoveringImage, m_pTempImageGray);
905  ImageProcessor::Erode(m_pTempImageGray, m_pHypothesesCoveringImage);
906  //m_pHypothesesCoveringImage->SaveToFile("/home/staff/schieben/SalHypRegionsCover.bmp");
907 
908  // get remaining salient regions
909  ImageProcessor::HistogramStretching(
910  m_pSaliencyImage, m_pSaliencyHypothesisRegionsImage, 0.5f, 1.0f);
911 
912  for (int i = 0; i < OLP_IMG_WIDTH * OLP_IMG_HEIGHT; i++)
913  {
914  m_pSaliencyHypothesisRegionsImage->pixels[i] =
915  (m_pHypothesesCoveringImage->pixels[i]) ? 0
916  : m_pSaliencyHypothesisRegionsImage->pixels[i];
917  }
918 
919  //m_pSaliencyHypothesisRegionsImage->SaveToFile("/homes/staff/schieben/SalHypRegions.bmp");
920 
921  // get and cluster points in remaining salient regions
922  std::vector<CHypothesisPoint*> aPointsInSalientRegions;
923  COLPTools::FilterForegroundPoints(aPointsFromDisparity,
924  m_pSaliencyHypothesisRegionsImage,
925  calibration,
926  aPointsInSalientRegions);
927 
928  std::vector<std::vector<CHypothesisPoint*>> aSalientRegionsPointsClusters;
929  COLPTools::ClusterXMeans(aPointsInSalientRegions,
930  1,
931  20,
933  aSalientRegionsPointsClusters);
934  ARMARX_VERBOSE_S << aSalientRegionsPointsClusters.size() << " clusters in salient regions";
935 
936  // add hypotheses
937  for (size_t i = 0; i < aSalientRegionsPointsClusters.size(); i++)
938  {
939  CVec3dArray aTempArray;
940 
941  for (size_t j = 0; j < aSalientRegionsPointsClusters.at(i).size(); j++)
942  {
943  aTempArray.AddElement(aSalientRegionsPointsClusters.at(i).at(j)->vPosition);
944  }
945 
946  RemoveOutliers(aTempArray, 1.5f, NULL);
947 
948  if (aTempArray.GetSize() > OLP_MIN_NUM_FEATURES)
949  {
950  pHypothesis = CreatePlaneHypothesisDescriptor(
951  aTempArray, aAllMSERs, aMSERSigmaPoints, pImageLeftColor, pImageLeftGrey);
952  pHypothesis->eType = CObjectHypothesis::eRGBD;
953  aObjectHypotheses.AddElement(pHypothesis);
954  }
955  }
956 
957  gettimeofday(&tEnd, 0);
958  tTimeDiff =
959  (1000 * tEnd.tv_sec + tEnd.tv_usec / 1000) - (1000 * tStart.tv_sec + tStart.tv_usec / 1000);
960  ARMARX_VERBOSE_S << "Time for saliency hypotheses: " << tTimeDiff << " ms";
961 
962 #endif
963 
964 
965  //**************************************************************************************************************
966  // sort the hypotheses in decreasing order
967  //**************************************************************************************************************
968 
969  int nSize;
970 
971  for (int i = 1; i < aObjectHypotheses.GetSize(); i++)
972  {
973  pHypothesis = aObjectHypotheses[i];
974  nSize = (int)aObjectHypotheses[i]->aNewPoints.size();
975  int j = i;
976 
977  while ((j > 0) && ((int)aObjectHypotheses[j - 1]->aNewPoints.size() < nSize))
978  {
979  aObjectHypotheses[j] = aObjectHypotheses[j - 1];
980  j--;
981  }
982 
983  aObjectHypotheses[j] = pHypothesis;
984  }
985 
986  // keep only as many hypotheses as wanted
987  for (int i = aObjectHypotheses.GetSize() - 1; i > OLP_MAX_NUM_HYPOTHESES; i--)
988  {
989  delete aObjectHypotheses[i];
990  aObjectHypotheses.DeleteElement(i);
991  }
992 
993  // give the hypotheses their numbers
994  for (int i = 0; i < aObjectHypotheses.GetSize(); i++)
995  {
996  aObjectHypotheses[i]->nHypothesisNumber = i;
997  }
998 
999 
1000  // // print hypothesis numbers and types
1001  // for (int i=0; i<aObjectHypotheses.GetSize(); i++)
1002  // {
1003  // if (i%2 == 0) ARMARX_VERBOSE_S << "\n");
1004  // ARMARX_VERBOSE_S << "Hyp. %d: ", i);
1005  // if (aObjectHypotheses[i]->eType == CObjectHypothesis::eCylinder)
1006  // {
1007  // ARMARX_VERBOSE_S << "C (%d p, r=%.1f) \t", (int)aObjectHypotheses[i]->aNewPoints.size(), aObjectHypotheses[i]->fRadius);
1008  // }
1009  // else if (aObjectHypotheses[i]->eType == CObjectHypothesis::ePlane)
1010  // {
1011  // ARMARX_VERBOSE_S << "P (%d p) \t", (int)aObjectHypotheses[i]->aNewPoints.size());
1012  // }
1013  // else if (aObjectHypotheses[i]->eType == CObjectHypothesis::eSphere)
1014  // {
1015  // ARMARX_VERBOSE_S << "S (%d p, r=%.1f) \t", (int)aObjectHypotheses[i]->aNewPoints.size(), aObjectHypotheses[i]->fRadius);
1016  // }
1017  // else
1018  // {
1019  // ARMARX_VERBOSE_S << "U (%d p) \t", (int)aObjectHypotheses[i]->aNewPoints.size());
1020  // }
1021  // }
1022  // ARMARX_VERBOSE_S << "\n\n");
1023 
1024 
1025  // clean up
1026  delete[] paPlanes;
1027  delete[] pPlaneNormals;
1028  delete[] pPlaneDs;
1029 
1030  for (int i = 0; i < nNumberOfPlanesAfterClustering; i++)
1031  {
1032  delete pPlanePointsAfterClustering[i];
1033  }
1034 
1035  delete[] pPlanePointsAfterClustering;
1036 
1037  delete[] paCylinders;
1038  delete[] pCylinderAxes;
1039  delete[] pCylinderCenters;
1040  delete[] pCylinderRadiuses;
1041 
1042  for (int i = 0; i < nNumberOfCylindersAfterClustering; i++)
1043  {
1044  delete pCylinderPointsAfterClustering[i];
1045  }
1046 
1047  delete[] pCylinderPointsAfterClustering;
1048  delete[] pCylinderAxesAfterClustering;
1049  delete[] pCylinderCentersAfterClustering;
1050  delete[] pCylinderRadiusesAfterClustering;
1051 
1052  delete[] paSpheres;
1053  delete[] pSphereCenters;
1054  delete[] pSphereRadiuses;
1055 
1056  delete[] pUnstructuredPointClusters;
1057 
1058  m_nIterations++;
1059 
1060 
1061  gettimeofday(&tEndAll, 0);
1062  tTimeDiff = (1000 * tEndAll.tv_sec + tEndAll.tv_usec / 1000) -
1063  (1000 * tStartAll.tv_sec + tStartAll.tv_usec / 1000);
1064  ARMARX_VERBOSE_S << "Time for complete hypothesis generation: " << tTimeDiff << " ms";
1065 }
1066 
1067 float
1068 CHypothesisGeneration::GetVariance(const CVec3dArray& avPoints, Vec3d& vMean)
1069 {
1070  vMean.x = 0;
1071  vMean.y = 0;
1072  vMean.z = 0;
1073  float fVariance = 0;
1074 
1075  // calculate mean
1076  for (int i = 0; i < avPoints.GetSize(); i++)
1077  {
1078  vMean.x += avPoints[i].x;
1079  vMean.y += avPoints[i].y;
1080  vMean.z += avPoints[i].z;
1081  }
1082 
1083  vMean.x /= (float)avPoints.GetSize();
1084  vMean.y /= (float)avPoints.GetSize();
1085  vMean.z /= (float)avPoints.GetSize();
1086 
1087  // calculate variance
1088  for (int i = 0; i < avPoints.GetSize(); i++)
1089  {
1090  fVariance += (vMean.x - avPoints[i].x) * (vMean.x - avPoints[i].x) +
1091  (vMean.y - avPoints[i].y) * (vMean.y - avPoints[i].y) +
1092  (vMean.z - avPoints[i].z) * (vMean.z - avPoints[i].z);
1093  }
1094 
1095  return (fVariance / (float)avPoints.GetSize());
1096 }
1097 
1098 void
1099 CHypothesisGeneration::RemoveOutliers(CVec3dArray& avPoints,
1100  float fStdDevFactor,
1101  std::vector<int>* paIndices)
1102 {
1103  if (avPoints.GetSize() < 9)
1104  {
1105  return;
1106  }
1107 
1108  Vec3d vMean;
1109  const float fStandardDeviation = sqrtf(GetVariance(avPoints, vMean));
1110  const float fThreshold2 =
1111  fStdDevFactor * fStdDevFactor * fStandardDeviation * fStandardDeviation;
1112 
1113  // remove all points that are further away from the mean than fStdDevFactor x standard deviation
1114  float fDist2;
1115 
1116  if (paIndices != NULL)
1117  {
1118  for (int i = 0; i < avPoints.GetSize(); i++)
1119  {
1120  fDist2 = (vMean.x - avPoints[i].x) * (vMean.x - avPoints[i].x) +
1121  (vMean.y - avPoints[i].y) * (vMean.y - avPoints[i].y) +
1122  (vMean.z - avPoints[i].z) * (vMean.z - avPoints[i].z);
1123 
1124  if (fDist2 > fThreshold2)
1125  {
1126  avPoints[i] = avPoints[avPoints.GetSize() - 1];
1127  paIndices->at(i) = paIndices->at(avPoints.GetSize() - 1);
1128  avPoints.DeleteElement(avPoints.GetSize() - 1);
1129  paIndices->pop_back();
1130  i--;
1131  }
1132  }
1133  }
1134  else
1135  {
1136  for (int i = 0; i < avPoints.GetSize(); i++)
1137  {
1138  fDist2 = (vMean.x - avPoints[i].x) * (vMean.x - avPoints[i].x) +
1139  (vMean.y - avPoints[i].y) * (vMean.y - avPoints[i].y) +
1140  (vMean.z - avPoints[i].z) * (vMean.z - avPoints[i].z);
1141 
1142  if (fDist2 > fThreshold2)
1143  {
1144  avPoints[i] = avPoints[avPoints.GetSize() - 1];
1145  avPoints.DeleteElement(avPoints.GetSize() - 1);
1146  i--;
1147  }
1148  }
1149  }
1150 }
1151 
1152 bool
1153 CHypothesisGeneration::FindCylinder(const CVec3dArray& avSamplePoints,
1154  const CVec3dArray& avAllPoints,
1155  const float fToleranceThreshold,
1156  const float fMaxRadius,
1157  CVec3dArray& avResultPoints,
1158  Vec3d& vCylinderAxis,
1159  Vec3d& vCylinderCenter,
1160  float& fCylinderRadius)
1161 {
1162  avResultPoints.Clear();
1163 
1164  const int nNumberOfSamples = avSamplePoints.GetSize();
1165 
1166  if (nNumberOfSamples < 5)
1167  {
1168  return false;
1169  }
1170 
1171  const int nNumberOfAllPoints = avAllPoints.GetSize();
1172 
1173  const Vec3d vZAxis = {0.0f, 0.0f, 1.0f};
1174 
1175  Vec3d vBestCylinderCenter, vBestCylinderAxis;
1176  float fBestCylinderRadius = 0;
1177  int nMaxNumberOfPointsOnCylinder = 0;
1178 
1179  Vec3d vAvgPoint = {0.0f, 0.0f, 0.0f};
1180 
1181  for (int i = 0; i < nNumberOfSamples; i++)
1182  {
1183  vAvgPoint.x += avSamplePoints[i].x;
1184  vAvgPoint.y += avSamplePoints[i].y;
1185  vAvgPoint.z += avSamplePoints[i].z;
1186  }
1187 
1188  vAvgPoint.x /= (float)nNumberOfSamples;
1189  vAvgPoint.y /= (float)nNumberOfSamples;
1190  vAvgPoint.z /= (float)nNumberOfSamples;
1191 
1192  CFloatMatrix mSamplePoints(3, nNumberOfSamples);
1193 
1194  for (int i = 0; i < nNumberOfSamples; i++)
1195  {
1196  mSamplePoints(0, i) = avSamplePoints[i].x - vAvgPoint.x;
1197  mSamplePoints(1, i) = avSamplePoints[i].y - vAvgPoint.y;
1198  mSamplePoints(2, i) = avSamplePoints[i].z - vAvgPoint.z;
1199  }
1200 
1201  CFloatMatrix mEigenVectors(3, 3);
1202  CFloatMatrix mEigenValues(1, 3);
1203  CFloatMatrix mProjection(2, 3);
1204  Mat3d mTransformation;
1205 
1206  LinearAlgebra::PCA(&mSamplePoints, &mEigenVectors, &mEigenValues);
1207 
1208  //ARMARX_VERBOSE_S << "\nAvg: ( %.1f %.1f %.1f )\n", vAvgPoint.x, vAvgPoint.y, vAvgPoint.z);
1209  //ARMARX_VERBOSE_S << "\nEigenvectors and Eigenvalues:\n");
1210  //ARMARX_VERBOSE_S << "( %.3f %.3f %.3f ) %.3f\n", mEigenVectors(0,0), mEigenVectors(0,1), mEigenVectors(0,2), sqrtf(mEigenValues(0,0)));
1211  //ARMARX_VERBOSE_S << "( %.3f %.3f %.3f ) %.3f\n", mEigenVectors(1,0), mEigenVectors(1,1), mEigenVectors(1,2), sqrtf(mEigenValues(0,1)));
1212  //ARMARX_VERBOSE_S << "( %.3f %.3f %.3f ) %.3f\n\n", mEigenVectors(2,0), mEigenVectors(2,1), mEigenVectors(2,2), sqrtf(mEigenValues(0,2)));
1213 
1214  Vec3d vTemp1, vTemp2;
1215 
1216  for (int n = 0; n < 3; n++)
1217  {
1218  switch (n)
1219  {
1220  case 0:
1221  // use eigenvector with largest eigenvalue as cylinder axis
1222  vCylinderAxis.x = mEigenVectors(0, 0);
1223  vCylinderAxis.y = mEigenVectors(0, 1);
1224  vCylinderAxis.z = mEigenVectors(0, 2);
1225  Math3d::NormalizeVec(vCylinderAxis);
1226 
1227  // matrix that projects the points to the subspace plane that is orthogonal to that
1228  // eigenvector, i.e. the plane spanned by the second and third eigenvector
1229  mProjection(0, 0) = mEigenVectors(1, 0);
1230  mProjection(0, 1) = mEigenVectors(1, 1);
1231  mProjection(0, 2) = mEigenVectors(1, 2);
1232  mProjection(1, 0) = mEigenVectors(2, 0);
1233  mProjection(1, 1) = mEigenVectors(2, 1);
1234  mProjection(1, 2) = mEigenVectors(2, 2);
1235 
1236  // matrix that transforms 3D points into the coordinate system given by
1237  // the cylinder axis and two orthogonal vectors
1238  mTransformation.r1 = mEigenVectors(0, 0);
1239  mTransformation.r2 = mEigenVectors(1, 0);
1240  mTransformation.r3 = mEigenVectors(2, 0);
1241  mTransformation.r4 = mEigenVectors(0, 1);
1242  mTransformation.r5 = mEigenVectors(1, 1);
1243  mTransformation.r6 = mEigenVectors(2, 1);
1244  mTransformation.r7 = mEigenVectors(0, 2);
1245  mTransformation.r8 = mEigenVectors(1, 2);
1246  mTransformation.r9 = mEigenVectors(2, 2);
1247 
1248  break;
1249 
1250  case 1:
1251  // use eigenvector with second largest eigenvalue as cylinder axis
1252  vCylinderAxis.x = mEigenVectors(1, 0);
1253  vCylinderAxis.y = mEigenVectors(1, 1);
1254  vCylinderAxis.z = mEigenVectors(1, 2);
1255  Math3d::NormalizeVec(vCylinderAxis);
1256 
1257  // matrix that projects the points to the subspace plane that is orthogonal to that
1258  // eigenvector, i.e. the plane spanned by the first and third eigenvector
1259  mProjection(0, 0) = mEigenVectors(0, 0);
1260  mProjection(0, 1) = mEigenVectors(0, 1);
1261  mProjection(0, 2) = mEigenVectors(0, 2);
1262  mProjection(1, 0) = mEigenVectors(2, 0);
1263  mProjection(1, 1) = mEigenVectors(2, 1);
1264  mProjection(1, 2) = mEigenVectors(2, 2);
1265 
1266  // matrix that transforms 3D points into the coordinate system given by
1267  // the cylinder axis and two orthogonal vectors
1268  mTransformation.r1 = mEigenVectors(1, 0);
1269  mTransformation.r2 = mEigenVectors(0, 0);
1270  mTransformation.r3 = mEigenVectors(2, 0);
1271  mTransformation.r4 = mEigenVectors(1, 1);
1272  mTransformation.r5 = mEigenVectors(0, 1);
1273  mTransformation.r6 = mEigenVectors(2, 1);
1274  mTransformation.r7 = mEigenVectors(1, 2);
1275  mTransformation.r8 = mEigenVectors(0, 2);
1276  mTransformation.r9 = mEigenVectors(2, 2);
1277 
1278  break;
1279 
1280  case 2:
1281 
1282  // use eigenvector with largest y value and turn it more towards the y-axis
1283  if (fabs(mEigenVectors(0, 1)) > fabs(mEigenVectors(1, 1)))
1284  {
1285  if (fabs(mEigenVectors(0, 1)) > fabs(mEigenVectors(2, 1)))
1286  {
1287  vCylinderAxis.x = mEigenVectors(0, 0);
1288  vCylinderAxis.y = 2.0f * mEigenVectors(0, 1);
1289  vCylinderAxis.z = mEigenVectors(0, 2);
1290  }
1291  else
1292  {
1293  vCylinderAxis.x = mEigenVectors(2, 0);
1294  vCylinderAxis.y = 2.0f * mEigenVectors(2, 1);
1295  vCylinderAxis.z = mEigenVectors(2, 2);
1296  }
1297  }
1298  else
1299  {
1300  if (fabs(mEigenVectors(1, 1)) > fabs(mEigenVectors(2, 1)))
1301  {
1302  vCylinderAxis.x = mEigenVectors(1, 0);
1303  vCylinderAxis.y = 2.0f * mEigenVectors(1, 1);
1304  vCylinderAxis.z = mEigenVectors(1, 2);
1305  Math3d::NormalizeVec(vCylinderAxis);
1306  }
1307  else
1308  {
1309  vCylinderAxis.x = mEigenVectors(2, 0);
1310  vCylinderAxis.y = 2.0f * mEigenVectors(2, 1);
1311  vCylinderAxis.z = mEigenVectors(2, 2);
1312  }
1313  }
1314 
1315  Math3d::NormalizeVec(vCylinderAxis);
1316 
1317  // create two axes orthogonal to the cylinder axis
1318  Math3d::CrossProduct(vCylinderAxis, vZAxis, vTemp1);
1319  Math3d::NormalizeVec(vTemp1);
1320  Math3d::CrossProduct(vCylinderAxis, vTemp1, vTemp2);
1321 
1322  // projection matrix to the plane that is orthogonal to the cylinder axis
1323  mProjection(0, 0) = vTemp1.x;
1324  mProjection(0, 1) = vTemp1.y;
1325  mProjection(0, 2) = vTemp1.z;
1326  mProjection(1, 0) = vTemp2.x;
1327  mProjection(1, 1) = vTemp2.y;
1328  mProjection(1, 2) = vTemp2.z;
1329 
1330  // matrix that transforms 3D points into the coordinate system given by
1331  // the cylinder axis and two orthogonal vectors
1332  mTransformation.r1 = vCylinderAxis.x;
1333  mTransformation.r2 = vTemp1.x;
1334  mTransformation.r3 = vTemp2.x;
1335  mTransformation.r4 = vCylinderAxis.y;
1336  mTransformation.r5 = vTemp1.y;
1337  mTransformation.r6 = vTemp2.y;
1338  mTransformation.r7 = vCylinderAxis.z;
1339  mTransformation.r8 = vTemp1.z;
1340  mTransformation.r9 = vTemp2.z;
1341 
1342  break;
1343 
1344  case 3:
1345  // use y-axis as cylinder axis
1346  vCylinderAxis.x = 0.0f;
1347  vCylinderAxis.y = 1.0f;
1348  vCylinderAxis.z = 0.0f;
1349 
1350  // matrix that projects the points to the subspace plane that is spanned
1351  // by the x- and z-axis
1352  mProjection(0, 0) = 1.0f;
1353  mProjection(0, 1) = 0.0f;
1354  mProjection(0, 2) = 0.0f;
1355  mProjection(1, 0) = 0.0f;
1356  mProjection(1, 1) = 0.0f;
1357  mProjection(1, 2) = 1.0f;
1358 
1359  // matrix that transforms 3D points into the coordinate system given by
1360  // the cylinder axis and two orthogonal vectors
1361  mTransformation.r1 = 0.0f;
1362  mTransformation.r2 = 1.0f;
1363  mTransformation.r3 = 0.0f;
1364  mTransformation.r4 = 1.0f;
1365  mTransformation.r5 = 0.0f;
1366  mTransformation.r6 = 0.0f;
1367  mTransformation.r7 = 0.0f;
1368  mTransformation.r8 = 0.0f;
1369  mTransformation.r9 = 1.0f;
1370  }
1371 
1372 
1373  // project the points
1374  CFloatMatrix mProjectedPoints(2, nNumberOfSamples);
1375  LinearAlgebra::MulMatMat(&mSamplePoints, &mProjection, &mProjectedPoints);
1376 
1377  //for (int i=0; i<nNumberOfSamples; i++)
1378  //{
1379  //ARMARX_VERBOSE_S << "3D: ( %.3f %.3f %.3f ) 2D: ( %.3f %.3f )\n", mSamplePoints(0,i), mSamplePoints(1,i), mSamplePoints(2,i), mProjectedPoints(0,i), mProjectedPoints(1,i));
1380  //fARMARX_VERBOSE_S << m_pOutFile, "%f %f\n", mProjectedPoints(0,i), mProjectedPoints(1,i));
1381  //}
1382  //ARMARX_VERBOSE_S << "\n\n");
1383 
1384  // sort the projected points by their first coordinate to support sampling
1385  QuickSort2DPointsX(mProjectedPoints, 0, nNumberOfSamples - 1);
1386 
1387  //for (int i=0; i<nNumberOfSamples; i++)
1388  //{
1389  // ARMARX_VERBOSE_S << "2D sorted %d: ( %.3f %.3f )\n", i, mProjectedPoints(0,i), mProjectedPoints(1,i));
1390  //}
1391  //ARMARX_VERBOSE_S << "\n\n");
1392 
1393  float fCenterX = 0, fCenterY = 0;
1394 
1395  // calculate the respective average of some points with low, medium and large x value,
1396  // then estimate the circle spanned by the three average points
1397  float xi = 0, yi = 0, xj = 0, yj = 0, xk = 0, yk = 0;
1398  //int nIndex;
1399  int nTwentyPercent = nNumberOfSamples / 5;
1400 
1401  //for (int i=0; i<nNumberOfSamples; i++)
1402  //{
1403  // nIndex = (rand() % (nTwentyPercent)); // between 0 and 20 %
1404  // xi += mProjectedPoints(0,nIndex);
1405  // yi += mProjectedPoints(1,nIndex);
1406  //
1407  // nIndex = 2*nTwentyPercent + (rand() % (nTwentyPercent)); // between 40 and 60 %
1408  // xj += mProjectedPoints(0,nIndex);
1409  // yj += mProjectedPoints(1,nIndex);
1410  //
1411  // nIndex = 4*nTwentyPercent + (rand() % (nTwentyPercent))-1; // between 80 and 100 %
1412  // xk += mProjectedPoints(0,nIndex);
1413  // yk += mProjectedPoints(1,nIndex);
1414  //}
1415  for (int i = 0; i < nTwentyPercent; i++) // between 0 and 20 %
1416  {
1417  xi += mProjectedPoints(0, i);
1418  yi += mProjectedPoints(1, i);
1419  }
1420 
1421  for (int i = 2 * nTwentyPercent; i < 3 * nTwentyPercent; i++) // between 40 and 60 %
1422  {
1423  xj += mProjectedPoints(0, i);
1424  yj += mProjectedPoints(1, i);
1425  }
1426 
1427  for (int i = 4 * nTwentyPercent; i < nNumberOfSamples; i++) // between 80 and 100 %
1428  {
1429  xk += mProjectedPoints(0, i);
1430  yk += mProjectedPoints(1, i);
1431  }
1432 
1433  const float fOneByNumUsedSamples = 1.0f / (float)nNumberOfSamples;
1434  xi *= fOneByNumUsedSamples;
1435  yi *= fOneByNumUsedSamples;
1436  xj *= fOneByNumUsedSamples;
1437  yj *= fOneByNumUsedSamples;
1438  xk *= fOneByNumUsedSamples;
1439  yk *= fOneByNumUsedSamples;
1440 
1441  // calculate the circumscribing circle of these three points
1442  const float fDelta1 = (xi * (yk - yj) + xj * (yi - yk) + xk * (yj - yi));
1443 
1444  //const float fDelta2 = (yi*(xk-xj)+yj*(xi-xk)+yk*(xj-xi)); //(xk-xj)*(yj-yi) - (xj-xi)*(yk-yi) <- wrong;
1445  //ARMARX_VERBOSE_S << "fDelta1: %.3f\n", fDelta1);
1446  //ARMARX_VERBOSE_S << "fDelta2: %.3f\n", fDelta2);
1447  //float fX, fY;
1448  if (fabs(fDelta1) > 0.001f)
1449  {
1450  fCenterX = 0.5f / fDelta1 *
1451  ((yk - yj) * (xi * xi + yi * yi) + (yi - yk) * (xj * xj + yj * yj) +
1452  (yj - yi) * (xk * xk + yk * yk));
1453  fCenterY = -0.5f / fDelta1 *
1454  ((xk - xj) * (xi * xi + yi * yi) + (xi - xk) * (xj * xj + yj * yj) +
1455  (xj - xi) * (xk * xk + yk * yk));
1456 
1457  //ARMARX_VERBOSE_S << "%.1f %.1f\n", xi, yi);
1458  //ARMARX_VERBOSE_S << "%.1f %.1f\n", xj, yj);
1459  //ARMARX_VERBOSE_S << "%.1f %.1f\n", xk, yk);
1460  //ARMARX_VERBOSE_S << "Center: ( %.1f %.1f )\n", fCenterX, fCenterY);
1461 
1462  //fARMARX_VERBOSE_S << m_pOutFile2, "%f %f\n", xi, yi);
1463  //fARMARX_VERBOSE_S << m_pOutFile2, "%f %f\n", xj, yj);
1464  //fARMARX_VERBOSE_S << m_pOutFile2, "%f %f\n", xk, yk);
1465  }
1466  else
1467  {
1468  return false; // TODO: find a better solution
1469  }
1470 
1471 
1472  /*
1473  int nNumberOfValidSampleCircles = 0;
1474  int nInd1a, nInd1b, nInd1c, nInd1d, nInd2a, nInd2b, nInd2c, nInd2d, nInd3a, nInd3b, nInd3c, nInd3d;
1475  //int nFivePercent = nNumberOfSamples/20;
1476  for (int i=0; (i<nNumberOfSamplesToUse) && (i<nNumberOfSamples); i++)
1477  {
1478  // choose three random points
1479  //nInd1a = 0*nFivePercent + (rand() % (3*nFivePercent)); // between 0 and 30 %
1480  //nInd1b = 0*nFivePercent + (rand() % (3*nFivePercent));
1481  //nInd1c = 0*nFivePercent + (rand() % (3*nFivePercent));
1482  //nInd1d = 0*nFivePercent + (rand() % (3*nFivePercent));
1483  //nInd2a = 8*nFivePercent + (rand() % (4*nFivePercent)); // between 35 and 65 %
1484  //nInd2b = 8*nFivePercent + (rand() % (4*nFivePercent));
1485  //nInd2c = 8*nFivePercent + (rand() % (4*nFivePercent));
1486  //nInd2d = 8*nFivePercent + (rand() % (4*nFivePercent));
1487  //nInd3a = 17*nFivePercent + (rand() % (3*nFivePercent)) - 1; // between 70 and 100 %
1488  //nInd3b = 17*nFivePercent + (rand() % (3*nFivePercent)) - 1;
1489  //nInd3c = 17*nFivePercent + (rand() % (3*nFivePercent)) - 1;
1490  //nInd3d = 17*nFivePercent + (rand() % (3*nFivePercent)) - 1;
1491  nInd1a = rand() % nNumberOfSamples;
1492  do { nInd2a = rand() % nNumberOfSamples; } while (nInd2a == nInd1a);
1493  do { nInd3a = rand() % nNumberOfSamples; } while ((nInd3a == nInd1a) || (nInd3a == nInd2a));
1494 
1495  //const float xi = 0.25f * (mProjectedPoints(0,nInd1a)+mProjectedPoints(0,nInd1b)+mProjectedPoints(0,nInd1c)+mProjectedPoints(0,nInd1d));
1496  //const float yi = 0.25f * (mProjectedPoints(1,nInd1a)+mProjectedPoints(1,nInd1b)+mProjectedPoints(1,nInd1c)+mProjectedPoints(1,nInd1d));
1497  //const float xj = 0.25f * (mProjectedPoints(0,nInd2a)+mProjectedPoints(0,nInd2b)+mProjectedPoints(0,nInd2c)+mProjectedPoints(0,nInd2d));
1498  //const float yj = 0.25f * (mProjectedPoints(1,nInd2a)+mProjectedPoints(1,nInd2b)+mProjectedPoints(1,nInd2c)+mProjectedPoints(1,nInd2d));
1499  //const float xk = 0.25f * (mProjectedPoints(0,nInd3a)+mProjectedPoints(0,nInd3b)+mProjectedPoints(0,nInd3c)+mProjectedPoints(0,nInd3d));
1500  //const float yk = 0.25f * (mProjectedPoints(1,nInd3a)+mProjectedPoints(1,nInd3b)+mProjectedPoints(1,nInd3c)+mProjectedPoints(1,nInd3d));
1501  const float xi = mProjectedPoints(0,nInd1a);
1502  const float yi = mProjectedPoints(1,nInd1a);
1503  const float xj = mProjectedPoints(0,nInd2a);
1504  const float yj = mProjectedPoints(1,nInd2a);
1505  const float xk = mProjectedPoints(0,nInd3a);
1506  const float yk = mProjectedPoints(1,nInd3a);
1507 
1508  // calculate the circumscribing circle of these three points and add its center to
1509  // the sum for averaging
1510  const float fDelta = (xi*(yk-yj)+xj*(yi-yk)+xk*(yj-yi)); //(xk-xj)*(yj-yi) - (xj-xi)*(yk-yi); <-wrong
1511  //ARMARX_VERBOSE_S << "fDelta1: %.3f\n", fDelta1);
1512  //ARMARX_VERBOSE_S << "fDelta2: %.3f\n", fDelta2);
1513  float fX, fY, fDist;
1514  if (fabs(fDelta)>0.001)
1515  {
1516  fX = 0.5f / fDelta * ( (yk-yj)*(xi*xi+yi*yi) + (yi-yk)*(xj*xj+yj*yj) + (yj-yi)*(xk*xk+yk*yk) );
1517  fY = - 0.5f / fDelta * ( (xk-xj)*(xi*xi+yi*yi) + (xi-xk)*(xj*xj+yj*yj) + (xj-xi)*(xk*xk+yk*yk) );
1518 
1519  fDist = (xi-fX)*(xi-fX) + (yi-fY)*(yi-fY);
1520  if ( fDist < 90000 )
1521  {
1522  fCenterX += fX;
1523  fCenterY += fY;
1524 
1525  fARMARX_VERBOSE_S << m_pOutFile, "%f %f\n", xi, yi);
1526  fARMARX_VERBOSE_S << m_pOutFile, "%f %f\n", xj, yj);
1527  fARMARX_VERBOSE_S << m_pOutFile, "%f %f\n", xk, yk);
1528  fARMARX_VERBOSE_S << m_pOutFile2, "%f %f\n", fX, fY);
1529  nNumberOfValidSampleCircles++;
1530  }
1531  }
1532  }
1533 
1534  fCenterX /= (float)nNumberOfValidSampleCircles;
1535  fCenterY /= (float)nNumberOfValidSampleCircles;
1536  */
1537 
1538 
1539  // calculate 3D position of the center
1540 
1541  Vec3d vCenter2D = {0.0f, fCenterX, fCenterY};
1542 
1543 
1544  Mat3d mInverseTransformation;
1545  Math3d::Invert(mTransformation, mInverseTransformation);
1546  Math3d::MulMatVec(mInverseTransformation, vCenter2D, vCylinderCenter);
1547 
1548  vCylinderCenter.x += vAvgPoint.x;
1549  vCylinderCenter.y += vAvgPoint.y;
1550  vCylinderCenter.z += vAvgPoint.z;
1551 
1552 
1553  // calculate optimal radius
1554  fCylinderRadius = 0;
1555 
1556  for (int i = 0; i < nNumberOfSamples; i++)
1557  {
1558  Math3d::SubtractVecVec(avSamplePoints[i], vCylinderCenter, vTemp1);
1559  Math3d::CrossProduct(vCylinderAxis, vTemp1, vTemp2);
1560  fCylinderRadius += Math3d::Length(vTemp2);
1561  }
1562 
1563  fCylinderRadius /= (float)nNumberOfSamples;
1564 
1565 
1566  //ARMARX_VERBOSE_S << "\nCylinder center: ( %.1f %.1f %.1f )\n", vCylinderCenter.x, vCylinderCenter.y, vCylinderCenter.z);
1567  //ARMARX_VERBOSE_S << "Cylinder axis: ( %.3f %.3f %.3f )\n", vCylinderAxis.x, vCylinderAxis.y, vCylinderAxis.z);
1568  //ARMARX_VERBOSE_S << "Cylinder radius: %.2f\n\n", fCylinderRadius);
1569 
1570  //fARMARX_VERBOSE_S << m_pOutFile3, "%f %f\n", fCenterX, fCenterY);
1571 
1572  // if the radius is realistic
1573  if (fCylinderRadius < fMaxRadius)
1574  {
1575 
1576  // calculate the plane spanned by the cylinder axis and the vector that is
1577  // orthogonal to the cylinder axis and the z-axis
1578  Vec3d vPlaneNormal;
1579  Math3d::CrossProduct(vCylinderAxis, vZAxis, vTemp1);
1580  Math3d::CrossProduct(vCylinderAxis, vTemp1, vPlaneNormal);
1581  const float fD = -Math3d::ScalarProduct(vPlaneNormal, vCylinderCenter);
1582  float fTemp;
1583 
1584  // check how many points belong to the cylinder surface
1585  float fDist;
1586  int nNumberOfPointsOnCylinder = 0;
1587 
1588  for (int i = 0; i < nNumberOfAllPoints; i++)
1589  {
1590  // accept only points that are on the side of the cylinder that is turned towards
1591  // the camera. If those points are put into the plane equation, the result has the
1592  // same sign as the result for (0,0,0), which is = fD
1593  fTemp = Math3d::ScalarProduct(vPlaneNormal, avAllPoints[i]) + fD;
1594 
1595  if (fTemp * fD > 0)
1596  {
1597  // accept only points within a tolerance margin around the cylinder surface
1598  Math3d::SubtractVecVec(avAllPoints[i], vCylinderCenter, vTemp1);
1599  Math3d::CrossProduct(vCylinderAxis, vTemp1, vTemp2);
1600  fDist = Math3d::Length(vTemp2);
1601  //ARMARX_VERBOSE_S << "%.2f\n", (fDist-fCylinderRadius));
1602 
1603  if (fabsf(fDist - fCylinderRadius) <= fToleranceThreshold)
1604  {
1605  nNumberOfPointsOnCylinder++;
1606  }
1607  }
1608  }
1609 
1610  if (nNumberOfPointsOnCylinder > nMaxNumberOfPointsOnCylinder)
1611  {
1612  nMaxNumberOfPointsOnCylinder = nNumberOfPointsOnCylinder;
1613 
1614  Math3d::SetVec(vBestCylinderCenter, vCylinderCenter);
1615  Math3d::SetVec(vBestCylinderAxis, vCylinderAxis);
1616  fBestCylinderRadius = fCylinderRadius;
1617  }
1618 
1619  //ARMARX_VERBOSE_S << "Points on the cylinder: %d\n\n", nNumberOfPointsOnCylinder);
1620  }
1621  }
1622 
1623  // if no cylinder seems realistic return false
1624  if (nMaxNumberOfPointsOnCylinder == 0)
1625  {
1626  return false;
1627  }
1628  else // return best cylinder
1629  {
1630  Math3d::SetVec(vCylinderCenter, vBestCylinderCenter);
1631  Math3d::SetVec(vCylinderAxis, vBestCylinderAxis);
1632  fCylinderRadius = fBestCylinderRadius;
1633 
1634  // add points belonging to the best cylinder to the result list
1635  float fDist;
1636 
1637  for (int i = 0; i < nNumberOfAllPoints; i++)
1638  {
1639  Math3d::SubtractVecVec(avAllPoints[i], vBestCylinderCenter, vTemp1);
1640  Math3d::CrossProduct(vBestCylinderAxis, vTemp1, vTemp2);
1641  fDist = Math3d::Length(vTemp2);
1642 
1643  //ARMARX_VERBOSE_S << "%.2f\n", (fDist-fCylinderRadius));
1644 
1645  if (fabsf(fDist - fBestCylinderRadius) <= fToleranceThreshold)
1646  {
1647  avResultPoints.AddElement(avAllPoints[i]);
1648  }
1649  }
1650 
1651  return true;
1652  }
1653 }
1654 
1655 void
1656 CHypothesisGeneration::QuickSort2DPointsX(CFloatMatrix& mPoints, int nLeft, int nRight)
1657 {
1658  int nPivotPos, i, j;
1659  float fPivotElemX, fTempElemX, fTempElemY;
1660 
1661  while (nRight - nLeft >= 16)
1662  {
1663  //ARMARX_VERBOSE_S << "l: %d r: %d\n", nLeft, nRight);
1664  // pick pivot
1665  nPivotPos = nLeft + rand() % (nRight - nLeft);
1666 
1667  // swap of a[left], a[pivot] helps to establish the invariant (?)
1668  fTempElemX = mPoints(0, nLeft);
1669  fTempElemY = mPoints(1, nLeft);
1670  mPoints(0, nLeft) = mPoints(0, nPivotPos);
1671  mPoints(1, nLeft) = mPoints(1, nPivotPos);
1672  mPoints(0, nPivotPos) = fTempElemX;
1673  mPoints(1, nPivotPos) = fTempElemY;
1674 
1675  // i runs from left, j from right, until they meet. when i is at an element that
1676  // is larger then the pivot and j is at an element that is smaller then the pivot,
1677  // those two elements are exchanged.
1678  fPivotElemX = mPoints(0, nLeft);
1679  i = nLeft;
1680  j = nRight;
1681 
1682  do
1683  {
1684  while (mPoints(0, i) < fPivotElemX)
1685  {
1686  i++;
1687  }
1688 
1689  while (mPoints(0, j) > fPivotElemX)
1690  {
1691  j--;
1692  }
1693 
1694  if (i < j)
1695  {
1696  // swap elements a[i], a[j]
1697  fTempElemX = mPoints(0, i);
1698  fTempElemY = mPoints(1, i);
1699  mPoints(0, i) = mPoints(0, j);
1700  mPoints(1, i) = mPoints(1, j);
1701  mPoints(0, j) = fTempElemX;
1702  mPoints(1, j) = fTempElemY;
1703 
1704  i++;
1705  j--;
1706  }
1707  } while (i < j);
1708 
1709  if (i < (nLeft + nRight) / 2)
1710  {
1711  QuickSort2DPointsX(mPoints, nLeft, j);
1712  nLeft = j;
1713  }
1714  else
1715  {
1716  QuickSort2DPointsX(mPoints, i, nRight);
1717  nRight = i;
1718  }
1719  }
1720 
1721  if (nLeft < nRight)
1722  {
1723  // insertion sort for small parts
1724  for (i = nLeft + 1; i <= nRight; i++)
1725  {
1726  fTempElemX = mPoints(0, i);
1727  fTempElemY = mPoints(1, i);
1728  j = i;
1729 
1730  while ((j > nLeft) && (mPoints(0, j - 1) > fTempElemX))
1731  {
1732  mPoints(0, j) = mPoints(0, j - 1);
1733  mPoints(1, j) = mPoints(1, j - 1);
1734  j--;
1735  }
1736 
1737  mPoints(0, j) = fTempElemX;
1738  mPoints(1, j) = fTempElemY;
1739  }
1740  }
1741 }
1742 
1743 void
1744 CHypothesisGeneration::ClusterPointsRegularGrid2D(const CVec3dArray& avPoints,
1745  const CCalibration* calibration,
1746  const int nNumSectionsX,
1747  const int nNumSectionsY,
1748  CVec3dArray*& pClusters,
1749  int& nNumClusters)
1750 {
1751  nNumClusters = nNumSectionsX * nNumSectionsY + (nNumSectionsX + 1) * (nNumSectionsY + 1);
1752  int nShiftOffset = nNumSectionsX * nNumSectionsY;
1753  pClusters = new CVec3dArray[nNumClusters];
1754  //for (int i=0; i<nNumClusters; i++) pClusters[i].Clear();
1755 
1756  const int nNumPoints = avPoints.GetSize();
1757  Vec2d vPoint2D;
1758  int nIndex, nIndexShifted;
1759  int nIntervalX = OLP_IMG_WIDTH / nNumSectionsX;
1760  int nIntervalY = OLP_IMG_HEIGHT / nNumSectionsY;
1761  int nIntervalX2 = OLP_IMG_WIDTH / (2 * nNumSectionsX);
1762  int nIntervalY2 = OLP_IMG_HEIGHT / (2 * nNumSectionsY);
1763 
1764  for (int i = 0; i < nNumPoints; i++)
1765  {
1766  calibration->CameraToImageCoordinates(avPoints[i], vPoint2D, false);
1767 
1768  nIndex = nNumSectionsX * ((int)vPoint2D.y / nIntervalY) + (int)vPoint2D.x / nIntervalX;
1769 
1770  nIndexShifted = (nNumSectionsX + 1) * (((int)vPoint2D.y + nIntervalY2) / nIntervalY) +
1771  ((int)vPoint2D.x + nIntervalX2) / nIntervalX;
1772 
1773  //ARMARX_VERBOSE_S << "Point: %.2f %.2f %.2f\n", avPoints[i].x, avPoints[i].y, avPoints[i].z);
1774 
1775  if (nIndex >= 0)
1776  {
1777  if (nIndex + nIndex < nNumClusters)
1778  {
1779  pClusters[nIndex].AddElement(avPoints[i]);
1780  }
1781 
1782  if (nShiftOffset + nIndexShifted < nNumClusters)
1783  {
1784  pClusters[nShiftOffset + nIndexShifted].AddElement(avPoints[i]);
1785  }
1786  }
1787  }
1788 
1789  /*
1790  ARMARX_VERBOSE_S << "\nCluster sizes:\n");
1791  int n=8;
1792  for (int i=0; i<n; i++)
1793  {
1794  for (int j=0; j<n; j++)
1795  {
1796  ARMARX_VERBOSE_S << "%d ", pClusters[n*i+j].GetSize());
1797  }
1798  ARMARX_VERBOSE_S << "\n");
1799  }
1800  ARMARX_VERBOSE_S << "\n");
1801 
1802  n = 4;
1803  for (int i=0; i<n; i++)
1804  {
1805  for (int j=0; j<n; j++)
1806  {
1807  ARMARX_VERBOSE_S << "%d ", pClusters[nNumSectionsSmall*nNumSectionsSmall + n*i+j].GetSize());
1808  }
1809  ARMARX_VERBOSE_S << "\n");
1810  }
1811  ARMARX_VERBOSE_S << "\n");
1812  */
1813 }
1814 
1815 /*
1816 bool CHypothesisGeneration::RANSACCylinders(const CVec3dArray& avPoints, const CCalibration* calibration,
1817  const float fToleranceThreshold, const float fMaxRadius, CVec3dArray& avCylinder)
1818 {
1819  // debug
1820  int nOrigin;
1821 
1822  // create a regular grid of clusters at several scales
1823  const int nNumScales = 7;
1824  CVec3dArray* ppRegularGridClusters[nNumScales];
1825  int pnNumGridClusters[nNumScales];
1826 
1827  ClusterPointsRegularGrid2D(avPoints, calibration, 16, 12, ppRegularGridClusters[0], pnNumGridClusters[0]);
1828  ClusterPointsRegularGrid2D(avPoints, calibration, 12, 9, ppRegularGridClusters[1], pnNumGridClusters[1]);
1829  ClusterPointsRegularGrid2D(avPoints, calibration, 8, 6, ppRegularGridClusters[2], pnNumGridClusters[2]);
1830  ClusterPointsRegularGrid2D(avPoints, calibration, 12, 6, ppRegularGridClusters[3], pnNumGridClusters[3]);
1831  ClusterPointsRegularGrid2D(avPoints, calibration, 12, 12, ppRegularGridClusters[4], pnNumGridClusters[4]);
1832  ClusterPointsRegularGrid2D(avPoints, calibration, 10, 8, ppRegularGridClusters[5], pnNumGridClusters[5]);
1833  ClusterPointsRegularGrid2D(avPoints, calibration, 9, 7, ppRegularGridClusters[6], pnNumGridClusters[6]);
1834 
1835  int nNumGridClusters = 0;
1836  for (int i=0; i<nNumScales; i++) nNumGridClusters += pnNumGridClusters[i];
1837 
1838  CVec3dArray* pRegularGridClusters = new CVec3dArray[nNumGridClusters];
1839  int nOffset = 0;
1840  for (int i=0; i<nNumScales; i++)
1841  {
1842  for (int j=0; j<pnNumGridClusters[i]; j++) pRegularGridClusters[nOffset+j] = ppRegularGridClusters[i][j];
1843  nOffset += pnNumGridClusters[i];
1844  }
1845 
1846  // for every cluster: try to find a cylinder and count the support for it in the whole image
1847  CVec3dArray avCylinderPoints;
1848  Vec3d vCylinderAxis, vCylinderCenter, vBestCylinderAxis, vBestCylinderCenter;
1849  float fCylinderRadius, fBestCylinderRadius;
1850  int nMaxSupport = 0;
1851  bool bFoundCylinder;
1852  const int nOverallNumberOfPoints = avPoints.GetSize();
1853  CVec3dArray avSample;
1854  const int nPreferredSampleSize = 20;
1855  for (int i=0; i<nNumGridClusters; i++)
1856  {
1857 
1858  int nIterationsOnThisCluster = 10 * pRegularGridClusters[i].GetSize() / (2*nPreferredSampleSize) + 1;
1859 
1860  for (int j=0; j<nIterationsOnThisCluster; j++)
1861  {
1862  if (j==0)
1863  {
1864  for (int k=0; k<pRegularGridClusters[i].GetSize(); k++) avSample.AddElement(pRegularGridClusters[i][k]);
1865  RemoveOutliers(pRegularGridClusters[i], 1.5f, NULL);
1866  }
1867  else
1868  {
1869  // select a random sample from the cluster
1870 
1871  int nSampleSize;
1872  if (pRegularGridClusters[i].GetSize() > 2*nPreferredSampleSize) nSampleSize = nPreferredSampleSize;
1873  else if (pRegularGridClusters[i].GetSize() > 10) nSampleSize = (pRegularGridClusters[i].GetSize()/2);
1874  else if (pRegularGridClusters[i].GetSize() >= 5) nSampleSize = 5;
1875  else continue;
1876 
1877  int nRandomIndex;
1878  //if (pRegularGridClusters[i].GetSize() < 30)
1879  {
1880  for (int k=0; k<pRegularGridClusters[i].GetSize(); k++) avSample.AddElement(pRegularGridClusters[i][k]);
1881  for (int n = pRegularGridClusters[i].GetSize(); n > nSampleSize; n--)
1882  {
1883  nRandomIndex = rand() % n;
1884  avSample.DeleteElement(nRandomIndex);
1885  }
1886  }
1887  }
1888 
1889 
1890  bFoundCylinder = FindCylinder(avSample, avPoints, fToleranceThreshold, fMaxRadius, avCylinderPoints, vCylinderAxis, vCylinderCenter, fCylinderRadius);
1891 
1892  avSample.Clear();
1893 
1894  if (bFoundCylinder)
1895  {
1896  int nNumberOfPointsOnCylinder = avCylinderPoints.GetSize();//0;
1897  //float fDist;
1898  //Vec3d vTemp1, vTemp2;
1899  //for (int k=0; k<nOverallNumberOfPoints; k++)
1900  //{
1901  // Math3d::SubtractVecVec(avPoints[k], vCylinderCenter, vTemp1);
1902  // Math3d::CrossProduct(vCylinderAxis, vTemp1, vTemp2);
1903  // fDist = Math3d::Length(vTemp2);
1904 
1905  // if (fabsf(fDist-fCylinderRadius) <= fToleranceThreshold)
1906  // {
1907  // nNumberOfPointsOnCylinder++;
1908  // }
1909  //}
1910 
1911  if (nNumberOfPointsOnCylinder > nMaxSupport)
1912  {
1913  nMaxSupport = nNumberOfPointsOnCylinder;
1914 
1915  Math3d::SetVec(vBestCylinderCenter, vCylinderCenter);
1916  Math3d::SetVec(vBestCylinderAxis, vCylinderAxis);
1917  fBestCylinderRadius = fCylinderRadius;
1918 
1919  if (i<pnNumGridClusters[0]) nOrigin = 0;
1920  else if (i<pnNumGridClusters[0]+pnNumGridClusters[1]) nOrigin = 1;
1921  else if (i<pnNumGridClusters[0]+pnNumGridClusters[1]+pnNumGridClusters[2]) nOrigin = 2;
1922  else if (i<pnNumGridClusters[0]+pnNumGridClusters[1]+pnNumGridClusters[2]+pnNumGridClusters[3]) nOrigin = 3;
1923  else if (i<pnNumGridClusters[0]+pnNumGridClusters[1]+pnNumGridClusters[2]+pnNumGridClusters[3]+pnNumGridClusters[4]) nOrigin = 4;
1924  else if (i<pnNumGridClusters[0]+pnNumGridClusters[1]+pnNumGridClusters[2]+pnNumGridClusters[3]+pnNumGridClusters[4]+pnNumGridClusters[5]) nOrigin = 5;
1925  else nOrigin = 42;
1926  }
1927  }
1928  }
1929  }
1930 
1931  avCylinder.Clear();
1932 
1933 
1934  if (nMaxSupport==0)
1935  {
1936  // if no cylinder was found, return false
1937  return false;
1938  }
1939  else
1940  {
1941  // return points belonging to the best cylinder
1942  float fDist;
1943  Vec3d vTemp1, vTemp2;
1944  for (int j=0; j<nOverallNumberOfPoints; j++)
1945  {
1946  Math3d::SubtractVecVec(avPoints[j], vBestCylinderCenter, vTemp1);
1947  Math3d::CrossProduct(vBestCylinderAxis, vTemp1, vTemp2);
1948  fDist = Math3d::Length(vTemp2);
1949 
1950  if (fabsf(fDist-fBestCylinderRadius) <= fToleranceThreshold)
1951  {
1952  avCylinder.AddElement(avPoints[j]);
1953  }
1954  }
1955 
1956  ARMARX_VERBOSE_S << "\nAxis: ( %.2f %.2f %.2f )\nRadius: %.1f Origin: %d\n", vBestCylinderAxis.x, vBestCylinderAxis.y, vBestCylinderAxis.z, fBestCylinderRadius, nOrigin);
1957 
1958  return true;
1959  }
1960 }
1961 */
1962 
1963 
1964 bool
1965 CHypothesisGeneration::RANSACCylinders2(const CVec3dArray& avPoints,
1966  const CCalibration* calibration,
1967  const float fToleranceThreshold,
1968  const float fMaxRadius,
1969  CVec3dArray& avCylinder,
1970  Vec3d& vCylinderAxis,
1971  Vec3d& vCylinderCenter,
1972  float& fCylinderRadius)
1973 {
1974  avCylinder.Clear();
1975  const int nMaxAxisIterations = (int)(OLP_EFFORT_MODIFICATOR * 8 + 15); // *10 + 30
1976  CVec3dArray avAxisBlacklist(nMaxAxisIterations);
1977  bool bBreakIfNextAxisIsBad = false;
1978  Vec3d vBestCylinderAxis, vBestCylinderCenter;
1979  float fBestRadius = 0;
1980 
1981  // timeval tStart, tEnd;
1982  // long tTimeDiff;
1983 
1984 
1985  // step 1: calculate local plane estimates and their surface normals to create the gauss map
1986 
1987  //gettimeofday(&tStart, 0);
1988 
1989  // segment the points into a regular grid to speed up nearest neighbour search
1990  int nNumGridClusters;
1991  //CVec3dArray* pRegularGridClusters;
1992  //ClusterPointsRegularGrid2D(avPoints, calibration, 8, 6, pRegularGridClusters, nNumGridClusters); // 8, 6
1993  nNumGridClusters = 1;
1994  const CVec3dArray* pRegularGridClusters = &avPoints;
1995 
1996  // for each point: find its 2 nearest neighbours, create a plane through these 3 points, calculate its normal
1997  // and add it to the gauss map
1998  const int nOverallNumberOfPoints = avPoints.GetSize();
1999  CVec3dArray avGaussMap(nOverallNumberOfPoints);
2000  CVec3dArray avCorrespondingPoints(nOverallNumberOfPoints);
2001  int nMaxSupport = 0;
2002 
2003 
2004  for (int i = 0; i < nNumGridClusters; i++)
2005  {
2006  const int nClusterSize = pRegularGridClusters[i].GetSize();
2007 
2008  if (nClusterSize >= 5)
2009  {
2010 #pragma omp parallel
2011  {
2012  CFloatMatrix mSampleMatrix(3, 5);
2013  CFloatMatrix mU(5, 5);
2014  CFloatMatrix mSigma(3, 5);
2015  CFloatMatrix mV(3, 3);
2016  Vec3d vPoint, vNeighbour1, vNeighbour2, vNeighbour3, vNeighbour4, vNormal, vMean,
2017  vTemp1, vTemp2;
2018  float fMinDist1, fMinDist2, fMinDist3, fMinDist4, fDist;
2019 
2020 #pragma omp for schedule(static, 10)
2021  for (int j = 0; j < nClusterSize; j++)
2022  {
2023  // select a point and find its 2 closest neighbours
2024  Math3d::SetVec(vPoint, pRegularGridClusters[i][j]);
2025  fMinDist1 = 1000000;
2026  fMinDist2 = 1000000;
2027  fMinDist3 = 1000000;
2028  fMinDist4 = 1000000;
2029 
2030  for (int k = 0; k < nClusterSize; k++)
2031  {
2032  if (k != j)
2033  {
2034  fDist = Math3d::Distance(vPoint, pRegularGridClusters[i][k]);
2035 
2036  if (fDist < fMinDist1)
2037  {
2038  fMinDist4 = fMinDist3;
2039  Math3d::SetVec(vNeighbour4, vNeighbour3);
2040  fMinDist3 = fMinDist2;
2041  Math3d::SetVec(vNeighbour3, vNeighbour2);
2042  fMinDist2 = fMinDist1;
2043  Math3d::SetVec(vNeighbour2, vNeighbour1);
2044  fMinDist1 = fDist;
2045  Math3d::SetVec(vNeighbour1, pRegularGridClusters[i][k]);
2046  }
2047  else if (fDist < fMinDist2)
2048  {
2049  fMinDist4 = fMinDist3;
2050  Math3d::SetVec(vNeighbour4, vNeighbour3);
2051  fMinDist3 = fMinDist2;
2052  Math3d::SetVec(vNeighbour3, vNeighbour2);
2053  fMinDist2 = fDist;
2054  Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][k]);
2055  }
2056  else if (fDist < fMinDist3)
2057  {
2058  fMinDist4 = fMinDist3;
2059  Math3d::SetVec(vNeighbour4, vNeighbour3);
2060  fMinDist3 = fDist;
2061  Math3d::SetVec(vNeighbour3, pRegularGridClusters[i][k]);
2062  }
2063  else if (fDist < fMinDist4)
2064  {
2065  fMinDist4 = fDist;
2066  Math3d::SetVec(vNeighbour4, pRegularGridClusters[i][k]);
2067  }
2068  }
2069  }
2070 
2071  // calculate the normal of these three points and add it to the gauss map
2072  /*Math3d::SubtractVecVec(vNeighbour1, vPoint, vTemp1);
2073  Math3d::SubtractVecVec(vNeighbour2, vPoint, vTemp2);
2074  Math3d::CrossProduct(vTemp1, vTemp2, vNormal);
2075  Math3d::NormalizeVec(vNormal);*/
2076 
2077  //if ( (fMinDist4 > 30.0f) && (fMinDist2 < 25.0f) )
2078  if (fMinDist2 < 25.0f)
2079  {
2080  // calculate the normal of the three closest points and add it to the gauss map
2081  Math3d::SubtractVecVec(vNeighbour1, vPoint, vTemp1);
2082  Math3d::SubtractVecVec(vNeighbour2, vPoint, vTemp2);
2083  Math3d::CrossProduct(vTemp1, vTemp2, vNormal);
2084  Math3d::NormalizeVec(vNormal);
2085 
2086  if (Math3d::Length(vNormal) > 0.9f)
2087  {
2088 #pragma omp critical
2089  {
2090  avGaussMap.AddElement(vNormal);
2091  avCorrespondingPoints.AddElement(vPoint);
2092  }
2093  }
2094  }
2095 
2096  if (fMinDist4 < 50.0f)
2097  {
2098  vMean.x = 0.2f * (vPoint.x + vNeighbour1.x + vNeighbour2.x + vNeighbour3.x +
2099  vNeighbour4.x);
2100  vMean.y = 0.2f * (vPoint.y + vNeighbour1.y + vNeighbour2.y + vNeighbour3.y +
2101  vNeighbour4.y);
2102  vMean.z = 0.2f * (vPoint.z + vNeighbour1.z + vNeighbour2.z + vNeighbour3.z +
2103  vNeighbour4.z);
2104 
2105  mSampleMatrix(0, 0) = vPoint.x - vMean.x;
2106  mSampleMatrix(1, 0) = vPoint.y - vMean.y;
2107  mSampleMatrix(2, 0) = vPoint.z - vMean.z;
2108  mSampleMatrix(0, 1) = vNeighbour1.x - vMean.x;
2109  mSampleMatrix(1, 1) = vNeighbour1.y - vMean.y;
2110  mSampleMatrix(2, 1) = vNeighbour1.z - vMean.z;
2111  mSampleMatrix(0, 2) = vNeighbour2.x - vMean.x;
2112  mSampleMatrix(1, 2) = vNeighbour2.y - vMean.y;
2113  mSampleMatrix(2, 2) = vNeighbour2.z - vMean.z;
2114  mSampleMatrix(0, 3) = vNeighbour3.x - vMean.x;
2115  mSampleMatrix(1, 3) = vNeighbour3.y - vMean.y;
2116  mSampleMatrix(2, 3) = vNeighbour3.z - vMean.z;
2117  mSampleMatrix(0, 4) = vNeighbour4.x - vMean.x;
2118  mSampleMatrix(1, 4) = vNeighbour4.y - vMean.y;
2119  mSampleMatrix(2, 4) = vNeighbour4.z - vMean.z;
2120 
2121  LinearAlgebra::SVD(&mSampleMatrix, &mSigma, &mU, &mV);
2122 
2123  vNormal.x = mV(2, 0);
2124  vNormal.y = mV(2, 1);
2125  vNormal.z = mV(2, 2);
2126  Math3d::NormalizeVec(vNormal);
2127 
2128  if (Math3d::Length(vNormal) < 0.9f)
2129  {
2130  //ARMARX_VERBOSE_S << "\n\np0: ( %f %f %f ) p1: ( %f %f %f ) p2: ( %f %f %f ) \nnormal: ( %f %f %f )\n\n\n",
2131  // vPoint.x, vPoint.y, vPoint.z, vNeighbour1.x, vNeighbour1.y, vNeighbour1.z,
2132  // vNeighbour2.x, vNeighbour2.y, vNeighbour2.z, vNormal.x, vNormal.y, vNormal.z);
2133  continue;
2134  }
2135 
2136 #pragma omp critical
2137  {
2138  avGaussMap.AddElement(vNormal);
2139  avCorrespondingPoints.AddElement(vPoint);
2140  }
2141  }
2142  }
2143  }
2144  //else if (nClusterSize == 4)
2145  //{
2146  // // get the three points that are closest to the mean
2147  // vMean.x = 0.25f * (pRegularGridClusters[i][0].x+pRegularGridClusters[i][1].x+pRegularGridClusters[i][2].x+pRegularGridClusters[i][3].x);
2148  // vMean.y = 0.25f * (pRegularGridClusters[i][0].y+pRegularGridClusters[i][1].y+pRegularGridClusters[i][2].y+pRegularGridClusters[i][3].y);
2149  // vMean.z = 0.25f * (pRegularGridClusters[i][0].z+pRegularGridClusters[i][1].z+pRegularGridClusters[i][2].z+pRegularGridClusters[i][3].z);
2150 
2151  // if (Math3d::Distance(vMean, pRegularGridClusters[i][0]) < Math3d::Distance(vMean, pRegularGridClusters[i][1]))
2152  // {
2153  // if (Math3d::Distance(vMean, pRegularGridClusters[i][2]) < Math3d::Distance(vMean, pRegularGridClusters[i][3]))
2154  // {
2155  // Math3d::SetVec(vPoint, pRegularGridClusters[i][0]);
2156  // Math3d::SetVec(vNeighbour1, pRegularGridClusters[i][2]);
2157 
2158  // if (Math3d::Distance(vMean, pRegularGridClusters[i][1]) < Math3d::Distance(vMean, pRegularGridClusters[i][3]))
2159  // {
2160  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][1]);
2161  // }
2162  // else
2163  // {
2164  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][3]);
2165  // }
2166  // }
2167  // else // 3 < 2
2168  // {
2169  // Math3d::SetVec(vPoint, pRegularGridClusters[i][0]);
2170  // Math3d::SetVec(vNeighbour1, pRegularGridClusters[i][3]);
2171 
2172  // if (Math3d::Distance(vMean, pRegularGridClusters[i][1]) < Math3d::Distance(vMean, pRegularGridClusters[i][2]))
2173  // {
2174  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][1]);
2175  // }
2176  // else
2177  // {
2178  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][2]);
2179  // }
2180  // }
2181  // }
2182  // else // 1 < 0
2183  // {
2184  // if (Math3d::Distance(vMean, pRegularGridClusters[i][2]) < Math3d::Distance(vMean, pRegularGridClusters[i][3]))
2185  // {
2186  // Math3d::SetVec(vPoint, pRegularGridClusters[i][1]);
2187  // Math3d::SetVec(vNeighbour1, pRegularGridClusters[i][2]);
2188 
2189  // if (Math3d::Distance(vMean, pRegularGridClusters[i][0]) < Math3d::Distance(vMean, pRegularGridClusters[i][3]))
2190  // {
2191  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][0]);
2192  // }
2193  // else
2194  // {
2195  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][3]);
2196  // }
2197  // }
2198  // else // 3 < 2
2199  // {
2200  // Math3d::SetVec(vPoint, pRegularGridClusters[i][1]);
2201  // Math3d::SetVec(vNeighbour1, pRegularGridClusters[i][3]);
2202 
2203  // if (Math3d::Distance(vMean, pRegularGridClusters[i][0]) < Math3d::Distance(vMean, pRegularGridClusters[i][2]))
2204  // {
2205  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][0]);
2206  // }
2207  // else
2208  // {
2209  // Math3d::SetVec(vNeighbour2, pRegularGridClusters[i][2]);
2210  // }
2211  // }
2212  // }
2213 
2214  // // calculate the normal of these three points and add it to the gauss map
2215  // Math3d::SubtractVecVec(vNeighbour1, vPoint, vTemp1);
2216  // Math3d::SubtractVecVec(vNeighbour2, vPoint, vTemp2);
2217  // Math3d::CrossProduct(vTemp1, vTemp2, vNormal);
2218  // Math3d::NormalizeVec(vNormal);
2219  // avGaussMap.AddElement(vNormal);
2220  // avCorrespondingPoints.AddElement(vPoint);
2221  //}
2222  //else if (nClusterSize == 3)
2223  //{
2224  // // calculate the normal of these three points and add it to the gauss map
2225  // Math3d::SubtractVecVec(pRegularGridClusters[i][1], pRegularGridClusters[i][0], vTemp1);
2226  // Math3d::SubtractVecVec(pRegularGridClusters[i][2], pRegularGridClusters[i][0], vTemp2);
2227  // Math3d::CrossProduct(vTemp1, vTemp2, vNormal);
2228  // Math3d::NormalizeVec(vNormal);
2229  // avGaussMap.AddElement(vNormal);
2230  // avCorrespondingPoints.AddElement(pRegularGridClusters[i][0]);
2231  //}
2232  }
2233  }
2234 
2235  //delete[] pRegularGridClusters;
2236 
2237  if (avGaussMap.GetSize() < OLP_MIN_NUM_FEATURES)
2238  {
2239  //ARMARX_VERBOSE_S << "\n(avGaussMap.GetSize() < 10)\n\n");
2240  return false;
2241  }
2242 
2243 
2244  //gettimeofday(&tEnd, 0);
2245  //tTimeDiff = (1000*tEnd.tv_sec+tEnd.tv_usec/1000) - (1000*tStart.tv_sec+tStart.tv_usec/1000);
2246  //ARMARX_VERBOSE_S << "Time for Gauss Map: %ld ms\n", tTimeDiff);
2247 
2248  //// debug
2249  //if (m_bTest) // && (m_nNumHypotheses>1))
2250  //{
2251  //for (int i=0; i<avGaussMap.GetSize(); i++)
2252  //{
2253  //avCylinder.AddElement(avGaussMap[i]);
2254  //avCylinder[2*i].x *= -100;
2255  //avCylinder[2*i].y *= -100;
2256  //avCylinder[2*i].z *= -100;
2257 
2258  //avCylinder.AddElement(avGaussMap[i]);
2259  //avCylinder[2*i+1].x *= 100;
2260  //avCylinder[2*i+1].y *= 100;
2261  //avCylinder[2*i+1].z *= 100;
2262 
2263  //avCylinder[2*i].z += 500;
2264  //avCylinder[2*i+1].z += 500;
2265 
2266  ////avCylinder.AddElement(avGaussMap[i]);
2267  ////if (avCylinder[i].z > 0)
2268  ////{
2269  ////avCylinder[i].x *= -100;
2270  ////avCylinder[i].y *= -100;
2271  ////avCylinder[i].z *= -100;
2272  ////}
2273  ////else
2274  ////{
2275  ////avCylinder[i].x *= 100;
2276  ////avCylinder[i].y *= 100;
2277  ////avCylinder[i].z *= 100;
2278  ////}
2279 
2280 
2281  ////avCylinder[i].x -= 150;
2282  ////avCylinder[i].y -= 100;
2283  ////avCylinder[i].z += 500;
2284  //}
2285  //m_bTest = false;
2286 
2287  //return true;
2288  //}
2289 
2290 
2291  // repeat nMaxAxisIterations and return the best found cylinder
2292  for (int n = 0; n < nMaxAxisIterations; n++)
2293  {
2294 
2295  // step 2: find a large circle on the gauss map (which is a sphere). this is equivalent to the
2296  // intersection of this sphere with a plane defined by (0,0,0) and two points on the sphere.
2297  // The resulting circle gives the normal of the cylinder that caused the circle in the gauss map.
2298 
2299  //gettimeofday(&tStart, 0);
2300 
2301  // use RANSAC to find the best plane/circle on the gauss map
2302  const int nGaussCircleIterations =
2303  (2 * avGaussMap.GetSize() > (int)(OLP_EFFORT_MODIFICATOR * 1000))
2304  ? (int)(OLP_EFFORT_MODIFICATOR * 1000)
2305  : 2 * avGaussMap.GetSize();
2306  const int nNumberOfPointsInGaussMap = avGaussMap.GetSize();
2307  const float fGaussMapThreshold = 0.15f;
2308  const float fBadAxisFactor = 0.1f; // 0.15
2309  int nMaxAxisSupport = 0;
2310  Vec3d vBestNormal;
2311 
2312 #pragma omp parallel
2313  {
2314  int nFirstIndex, nSecondIndex, nSupport;
2315  Vec3d vPoint1, vPoint2, vNormal;
2316  bool bCloseToBadAxis;
2317 
2318 #pragma omp for schedule(static, 16)
2319  for (int i = 0; i < nGaussCircleIterations; i++)
2320  {
2321  // identify 2 different random points
2322  srand((rand() % 17) * i + i);
2323  nFirstIndex = rand() % nNumberOfPointsInGaussMap;
2324 
2325  do
2326  {
2327  nSecondIndex = rand() % nNumberOfPointsInGaussMap;
2328  } while (nSecondIndex == nFirstIndex);
2329 
2330  vPoint1 = avGaussMap[nFirstIndex];
2331  vPoint2 = avGaussMap[nSecondIndex];
2332 
2333  // calculate plane defined by them and (0,0,0)
2334  // easy because one point is (0,0,0) => p1-p0 = p1 etc, plane parameter d=0
2335  Math3d::CrossProduct(vPoint1, vPoint2, vNormal);
2336  Math3d::NormalizeVec(vNormal);
2337 
2338  // make sure normal is not (0,0,0). that may happen when p1=p2.
2339  if (Math3d::ScalarProduct(vNormal, vNormal) > 0.9f)
2340  {
2341  // check if it is close to an axis that led to a bad cylinder
2342  bCloseToBadAxis = false;
2343 
2344  for (int j = 0; j < avAxisBlacklist.GetSize(); j++)
2345  {
2346  bCloseToBadAxis |=
2347  (fabsf(Math3d::ScalarProduct(vNormal, avAxisBlacklist[j])) >
2348  1.0f - fBadAxisFactor * fGaussMapThreshold); // 0.2
2349  }
2350 
2351  if (!bCloseToBadAxis)
2352  {
2353  // count support
2354  nSupport = 0;
2355 
2356  for (int j = 0; j < nNumberOfPointsInGaussMap; j++)
2357  {
2358  if (fabsf(Math3d::ScalarProduct(vNormal, avGaussMap[j])) <
2359  fGaussMapThreshold)
2360  {
2361  nSupport++;
2362  }
2363  }
2364 
2365  // store if it is the current maximum
2366  if (nSupport > nMaxAxisSupport)
2367  {
2368 #pragma omp critical
2369  if (nSupport > nMaxAxisSupport)
2370  {
2371  nMaxAxisSupport = nSupport;
2372  Math3d::SetVec(vBestNormal, vNormal);
2373  }
2374  }
2375  }
2376  }
2377  }
2378  }
2379 
2380  //gettimeofday(&tEnd, 0);
2381  //tTimeDiff = (1000*tEnd.tv_sec+tEnd.tv_usec/1000) - (1000*tStart.tv_sec+tStart.tv_usec/1000);
2382  //ARMARX_VERBOSE_S << "Time for Gauss Map circle: %ld ms\n", tTimeDiff);
2383 
2384 
2385  if (nMaxAxisSupport < OLP_MIN_NUM_FEATURES)
2386  {
2387  //ARMARX_VERBOSE_S << "%d\n", n);
2388  if (bBreakIfNextAxisIsBad)
2389  {
2390  //ARMARX_VERBOSE_S << "no axis found after %d iterations\n", n);
2391  break;
2392  //continue;
2393  }
2394  else if (2 * n > nMaxAxisIterations)
2395  {
2396  bBreakIfNextAxisIsBad = true;
2397  //ARMARX_VERBOSE_S << "c ");
2398  avAxisBlacklist.AddElement(vBestNormal);
2399  continue;
2400  }
2401  else
2402  {
2403  //ARMARX_VERBOSE_S << "c ");
2404  avAxisBlacklist.AddElement(vBestNormal);
2405  continue;
2406  }
2407  }
2408 
2409  //if (Math3d::Length(vBestNormal) < 0.9f)
2410  //{
2411  // ARMARX_VERBOSE_S << "\n\n\n --- bad axis ---\n\n\n");
2412  //}
2413 
2414  //ARMARX_VERBOSE_S << "Best normal: ( %f %f %f )\n", vBestNormal.x, vBestNormal.y, vBestNormal.z);
2415 
2416 
2417  // collect the points whose local normals constitute that circle
2418  CVec3dArray avCylinderCandidates;
2419 
2420  for (int j = 0; j < nNumberOfPointsInGaussMap; j++)
2421  {
2422  if (fabsf(Math3d::ScalarProduct(vBestNormal, avGaussMap[j])) <=
2423  1.0f * fGaussMapThreshold)
2424  {
2425  // check if the point is already amongst the candidates
2426  bool bDouble = false;
2427 
2428  for (int i = 0; i < avCylinderCandidates.GetSize(); i++)
2429  {
2430  if (avCorrespondingPoints[j].x == avCylinderCandidates[i].x)
2431  {
2432  if ((avCorrespondingPoints[j].y == avCylinderCandidates[i].y) &&
2433  (avCorrespondingPoints[j].z == avCylinderCandidates[i].z))
2434  {
2435  bDouble = true;
2436  break;
2437  }
2438  }
2439  }
2440 
2441  if (!bDouble)
2442  {
2443  avCylinderCandidates.AddElement(avCorrespondingPoints[j]);
2444  }
2445 
2446  //ARMARX_VERBOSE_S << "c.p.: ( %.1f %.1f %.1f )\n", avCorrespondingPoints[j].x, avCorrespondingPoints[j].y, avCorrespondingPoints[j].z);
2447  }
2448  }
2449 
2450 
2451  // project the points to the plane orthogonal to the cylinder axis
2452  const Vec3d vCylinderAxis = {vBestNormal.x, vBestNormal.y, vBestNormal.z};
2453  const Vec3d vZAxis = {0, 0, 1};
2454  Vec3d vTemp1, vTemp2;
2455  Math3d::CrossProduct(vCylinderAxis, vZAxis, vTemp1);
2456  Math3d::CrossProduct(vCylinderAxis, vTemp1, vTemp2);
2457  const Mat3d mTransform = {vCylinderAxis.x,
2458  vTemp1.x,
2459  vTemp2.x,
2460  vCylinderAxis.y,
2461  vTemp1.y,
2462  vTemp2.y,
2463  vCylinderAxis.z,
2464  vTemp1.z,
2465  vTemp2.z};
2466  Mat3d mTransformInv;
2467  Math3d::Invert(mTransform, mTransformInv);
2468  const int nNumCylinderCandidates = avCylinderCandidates.GetSize();
2469  CVec3dArray avCylinderCandidatesTransformed(nNumCylinderCandidates);
2470 
2471  for (int i = 0; i < nNumCylinderCandidates; i++)
2472  {
2473  Math3d::MulMatVec(mTransform, avCylinderCandidates[i], vTemp1);
2474  avCylinderCandidatesTransformed.AddElement(vTemp1);
2475  }
2476 
2477 
2478  // choose 3 random points and calculate a circle on the plane orthogonal to the cylinder axis
2479  // get the best cylinder that is defined by the axis and such a circle
2480 
2481  //ARMARX_VERBOSE_S << "nNumCylinderCandidates: %d\n", nNumCylinderCandidates);
2482 
2483  //gettimeofday(&tStart, 0);
2484  if (nNumCylinderCandidates < OLP_MIN_NUM_FEATURES)
2485  {
2486  //ARMARX_VERBOSE_S << "\n(nNumCylinderCandidates < 10)\n\n");
2487  continue;
2488  }
2489 
2490  const float fMaxRadius2 =
2491  fMaxRadius * fMaxRadius; // avoid sqrt in the loop as far as possible
2492  const float fToleranceThreshold2 = fToleranceThreshold * fToleranceThreshold;
2493  const int nMaxCircleIterations =
2494  (int)(OLP_EFFORT_MODIFICATOR * 2000.0f); // 5000 (frueher: 12000)
2495  const int nCircleIterationsPrep =
2496  (int)(OLP_EFFORT_MODIFICATOR * (float)nNumCylinderCandidates * 4.0f *
2497  sqrtf((float)nNumCylinderCandidates)); // 5.0
2498  const int nCircleIterations = (nCircleIterationsPrep < nMaxCircleIterations)
2499  ? nCircleIterationsPrep
2500  : nMaxCircleIterations;
2501  int nMaxSupportForThisAxis = OLP_MIN_NUM_FEATURES - 1;
2502 
2503  // const int nSqrtNumCylinderCandidates = 20;//(nNumCylinderCandidates>225) ? ((int)(sqrtf((float)nNumCylinderCandidates))) : 15;
2504  // int* pRandomIndices = new int[nSqrtNumCylinderCandidates];
2505  // for (int i=0; i<nSqrtNumCylinderCandidates; i++)
2506  // {
2507  // pRandomIndices[i] = rand() % nNumCylinderCandidates;
2508  // }
2509 
2510  //ARMARX_VERBOSE_S << "#CPUs: %d, #threads: %d, max#threads: %d, parallel: %d\n", omp_get_num_procs(), omp_get_num_threads(), omp_get_max_threads(), omp_in_parallel());
2511 
2512 #pragma omp parallel
2513  {
2514  int nFirstIndex, nSecondIndex, nThirdIndex, nSupport;
2515  float xi, yi, xj, yj, xk, yk, fCenterX, fCenterY, fRadius2, fDist2;
2516  Vec3d vCylinderCenter, vTemp1, vTemp2;
2517  int nMaxSupportLocal = OLP_MIN_NUM_FEATURES - 1;
2518  Vec3d vBestCylinderCenterLocal;
2519  float fBestRadiusLocal = 0;
2520 
2521 #pragma omp for schedule(static, 32)
2522  for (int i = 0; i < nCircleIterations; i++)
2523  {
2524  //if (i==42) ARMARX_VERBOSE_S << "#CPUs: %d, #threads: %d, max#threads: %d, parallel: %d\n", omp_get_num_procs(), omp_get_num_threads(), omp_get_max_threads(), omp_in_parallel());
2525 
2526  // get 3 random points and calculate the circle that they define
2527  srand((rand() % 17) * i + i);
2528  nFirstIndex = rand() % nNumCylinderCandidates;
2529 
2530  do
2531  {
2532  nSecondIndex = rand() % nNumCylinderCandidates;
2533  } while (nSecondIndex == nFirstIndex);
2534 
2535  do
2536  {
2537  nThirdIndex = rand() % nNumCylinderCandidates;
2538  } while (nThirdIndex == nFirstIndex || nThirdIndex == nSecondIndex);
2539 
2540  xi = avCylinderCandidatesTransformed[nFirstIndex].y;
2541  yi = avCylinderCandidatesTransformed[nFirstIndex].z;
2542  xj = avCylinderCandidatesTransformed[nSecondIndex].y;
2543  yj = avCylinderCandidatesTransformed[nSecondIndex].z;
2544  xk = avCylinderCandidatesTransformed[nThirdIndex].y;
2545  yk = avCylinderCandidatesTransformed[nThirdIndex].z;
2546  //ARMARX_VERBOSE_S << "%.3f %.3f %.3f %.3f %.3f %.3f\n", xi, yi, xj, yj, xk, yk);
2547 
2548  const float fDelta = (xi * (yk - yj) + xj * (yi - yk) + xk * (yj - yi));
2549 
2550  //ARMARX_VERBOSE_S << "fDelta: %f\n", fDelta);
2551  if (fabs(fDelta) > 0.001f)
2552  {
2553  fCenterX = 0.5f / fDelta *
2554  ((yk - yj) * (xi * xi + yi * yi) + (yi - yk) * (xj * xj + yj * yj) +
2555  (yj - yi) * (xk * xk + yk * yk));
2556  fCenterY = -0.5f / fDelta *
2557  ((xk - xj) * (xi * xi + yi * yi) + (xi - xk) * (xj * xj + yj * yj) +
2558  (xj - xi) * (xk * xk + yk * yk));
2559  fRadius2 = (fCenterX - xi) * (fCenterX - xi) +
2560  (fCenterY - yi) * (fCenterY - yi); // avoid sqrt here
2561  }
2562  else
2563  {
2564  continue;
2565  }
2566 
2567 
2568  // if the radius is realistic
2569  if (fRadius2 < fMaxRadius2)
2570  {
2571  // restrict the radius further
2572  //fRadius2 = (fRadius2 < 0.7*fMaxRadius2) ? fRadius2 : 0.7*fMaxRadius2;
2573 
2574  // calculate the cylinder parameters
2575  Math3d::SetVec(vTemp1, 0, fCenterX, fCenterY);
2576  Math3d::MulMatVec(mTransformInv, vTemp1, vCylinderCenter);
2577 
2578  // calculate the plane spanned by the cylinder axis and the vector that is
2579  // orthogonal to the cylinder axis and the z-axis
2580  Vec3d vPlaneNormal;
2581  Math3d::CrossProduct(vCylinderAxis, vZAxis, vTemp1);
2582  Math3d::CrossProduct(vCylinderAxis, vTemp1, vPlaneNormal);
2583  const float fD = -Math3d::ScalarProduct(vPlaneNormal, vCylinderCenter);
2584  float fTemp;
2585 
2586  //ARMARX_VERBOSE_S << "center: (%.1f %.1f %.1f) radius: %.2f\n", vCylinderCenter.x, vCylinderCenter.y, vCylinderCenter.z, fRadius);
2587 
2588  // // first count the support for this cylinder using a randomized sample (23800ms)
2589  // bool bDoIntensiveCheck = true;
2590  // nSupport = 0;
2591  // for (int j=0; j<nSqrtNumCylinderCandidates; j++)
2592  // {
2593  // int k = pRandomIndices[j];
2594  // // accept only points that are on the side of the cylinder that is turned towards
2595  // // the camera. If those points are put into the plane equation, the result has the
2596  // // same sign as the result for (0,0,0), which is = fD
2597  // fTemp = Math3d::ScalarProduct(vPlaneNormal, avCylinderCandidates[k]) + fD;
2598  // if (fTemp*fD > 0)
2599  // {
2600  // Math3d::SubtractVecVec(avCylinderCandidates[k], vCylinderCenter, vTemp1);
2601  // Math3d::CrossProduct(vCylinderAxis, vTemp1, vTemp2);
2602  // fTemp = Math3d::ScalarProduct(vTemp2, vTemp2);
2603  //
2604  // // only here one sqrt is necessary
2605  // fDist2 = fTemp - 2.0f*sqrtf(fTemp*fRadius2) + fRadius2;
2606  //
2607  // if (fDist2 < fToleranceThreshold2)
2608  // {
2609  // nSupport++;
2610  // }
2611  // }
2612  // }
2613  // if (nSqrtNumCylinderCandidates*nSupport < nMaxSupportLocal)
2614  // {
2615  // bDoIntensiveCheck = false;
2616  // }
2617  //
2618  // // if randomized evaluation indicates a good candidate, do the full support check
2619  // if (bDoIntensiveCheck)
2620  {
2621  // count the support for this cylinder
2622  nSupport = 0;
2623 
2624  for (int j = 0; j < nNumCylinderCandidates; j++)
2625  {
2626  // accept only points that are on the side of the cylinder that is turned towards
2627  // the camera. If those points are put into the plane equation, the result has the
2628  // same sign as the result for (0,0,0), which is = fD
2629  fTemp =
2630  Math3d::ScalarProduct(vPlaneNormal, avCylinderCandidates[j]) + fD;
2631 
2632  if (fTemp * fD > 0)
2633  {
2634  Math3d::SubtractVecVec(
2635  avCylinderCandidates[j], vCylinderCenter, vTemp1);
2636  Math3d::CrossProduct(vCylinderAxis, vTemp1, vTemp2);
2637  fTemp = Math3d::ScalarProduct(vTemp2, vTemp2);
2638 
2639  // only here one sqrt is necessary
2640  fDist2 = fTemp - 2.0f * sqrtf(fTemp * fRadius2) + fRadius2;
2641 
2642  if (fDist2 < fToleranceThreshold2)
2643  {
2644  nSupport++;
2645  }
2646  }
2647  }
2648 
2649  if (nSupport > nMaxSupportLocal)
2650  {
2651  nMaxSupportLocal = nSupport;
2652  Math3d::SetVec(vBestCylinderCenterLocal, vCylinderCenter);
2653  fBestRadiusLocal = sqrtf(fRadius2);
2654  }
2655  }
2656  }
2657  }
2658 
2659 #pragma omp critical
2660  if (nMaxSupportLocal > nMaxSupportForThisAxis)
2661  {
2662  nMaxSupportForThisAxis = nMaxSupportLocal;
2663 
2664  if (nMaxSupportLocal > nMaxSupport)
2665  {
2666  nMaxSupport = nMaxSupportLocal;
2667  Math3d::SetVec(vBestCylinderCenter, vBestCylinderCenterLocal);
2668  Math3d::SetVec(vBestCylinderAxis, vCylinderAxis);
2669  fBestRadius = fBestRadiusLocal;
2670  }
2671  }
2672  }
2673 
2674  //if (nMaxSupportForThisAxis == nMaxSupport) ARMARX_VERBOSE_S << "%d ", n);
2675 
2676  //ARMARX_VERBOSE_S << "Max support: %d\n", nMaxSupport);
2677 
2678  // delete[] pRandomIndices;
2679 
2680  avAxisBlacklist.AddElement(vCylinderAxis);
2681 
2682  //gettimeofday(&tEnd, 0);
2683  //tTimeDiff = (1000*tEnd.tv_sec+tEnd.tv_usec/1000) - (1000*tStart.tv_sec+tStart.tv_usec/1000);
2684  //ARMARX_VERBOSE_S << "Time for cylinder radius: %ld ms\n", tTimeDiff);
2685  }
2686 
2687 
2688  if (nMaxSupport >= OLP_MIN_NUM_FEATURES)
2689  {
2690  // return the best cylinder
2691  float fDist;
2692  Vec3d vTemp1, vTemp2;
2693 
2694  for (int j = 0; j < nOverallNumberOfPoints; j++)
2695  {
2696  Math3d::SubtractVecVec(avPoints[j], vBestCylinderCenter, vTemp1);
2697  Math3d::CrossProduct(vBestCylinderAxis, vTemp1, vTemp2);
2698  fDist = Math3d::Length(vTemp2);
2699 
2700  if (fabsf(fDist - fBestRadius) <= fToleranceThreshold)
2701  {
2702  avCylinder.AddElement(avPoints[j]);
2703  }
2704  }
2705 
2706  //ARMARX_VERBOSE_S << "\nAxis: ( %.2f %.2f %.2f )\nRadius: %.1f\n\n", vBestCylinderAxis.x, vBestCylinderAxis.y, vBestCylinderAxis.z, fBestRadius);
2707 
2708  Math3d::SetVec(vCylinderAxis, vBestCylinderAxis);
2709  Math3d::SetVec(vCylinderCenter, vBestCylinderCenter);
2710  fCylinderRadius = fBestRadius;
2711 
2712  //ARMARX_VERBOSE_S << "cylinder: %d p\n", avCylinder.GetSize());
2713 
2714  return true;
2715  }
2716  else
2717  {
2718  return false;
2719  }
2720 }
2721 
2724  std::vector<CMSERDescriptor3D*>& aMSERs,
2725  std::vector<Vec3d>& aSigmaPoints,
2726  const CByteImage* pLeftColorImage,
2727  const CByteImage* pLeftGreyImage)
2728 {
2729  CObjectHypothesis* hResult = new CObjectHypothesis();
2730 
2731  hResult->eType = CObjectHypothesis::ePlane;
2732 
2733  const int nNum3dPoints = avPlanePoints.GetSize();
2734 
2735  //#pragma omp parallel
2736  {
2737  CHypothesisPoint* pPoint;
2738 
2739  //#pragma omp for schedule(static, 5)
2740  for (int i = 0; i < nNum3dPoints; i++)
2741  {
2742  pPoint = new CHypothesisPoint();
2743 
2744  if (CreateFeatureDescriptorForPoint(pPoint,
2745  avPlanePoints[i],
2746  aMSERs,
2747  aSigmaPoints,
2748  pLeftColorImage,
2749  pLeftGreyImage))
2750  {
2751  //#pragma omp critical
2752  hResult->aNewPoints.push_back(pPoint);
2753  }
2754  else
2755  {
2756  delete pPoint;
2757  }
2758  }
2759  }
2760 
2761  // calculate the mean of the plane points
2762  Math3d::SetVec(hResult->vCenter, 0, 0, 0);
2763 
2764  for (int i = 0; i < nNum3dPoints; i++)
2765  {
2766  hResult->vCenter.x += avPlanePoints[i].x;
2767  hResult->vCenter.y += avPlanePoints[i].y;
2768  hResult->vCenter.z += avPlanePoints[i].z;
2769  }
2770 
2771  hResult->vCenter.x /= (float)nNum3dPoints;
2772  hResult->vCenter.y /= (float)nNum3dPoints;
2773  hResult->vCenter.z /= (float)nNum3dPoints;
2774 
2775  // calculate the plane parameters. this is done by calculation of the eigenvectors of the point cloud.
2776  // the two largest eigenvectors span the plane, the third one is the plane normal.
2777  CFloatMatrix mPoints(3, nNum3dPoints);
2778  CFloatMatrix mEigenVectors(3, 3);
2779  CFloatMatrix mEigenValues(1, 3);
2780 
2781  for (int i = 0; i < nNum3dPoints; i++)
2782  {
2783  mPoints(0, i) = avPlanePoints[i].x - hResult->vCenter.x;
2784  mPoints(1, i) = avPlanePoints[i].y - hResult->vCenter.y;
2785  mPoints(2, i) = avPlanePoints[i].z - hResult->vCenter.z;
2786  }
2787 
2788  LinearAlgebra::PCA(&mPoints, &mEigenVectors, &mEigenValues);
2789 
2790  // make sure the normal points towards the camera
2791  if (mEigenVectors(2, 2) < 0)
2792  {
2793  hResult->vNormal.x = mEigenVectors(2, 0);
2794  hResult->vNormal.y = mEigenVectors(2, 1);
2795  hResult->vNormal.z = mEigenVectors(2, 2);
2796 
2797  hResult->vSecondAxis.x = mEigenVectors(0, 0);
2798  hResult->vSecondAxis.y = mEigenVectors(0, 1);
2799  hResult->vSecondAxis.z = mEigenVectors(0, 2);
2800  }
2801  else
2802  {
2803  hResult->vNormal.x = -mEigenVectors(2, 0);
2804  hResult->vNormal.y = -mEigenVectors(2, 1);
2805  hResult->vNormal.z = -mEigenVectors(2, 2);
2806 
2807  hResult->vSecondAxis.x = -mEigenVectors(0, 0);
2808  hResult->vSecondAxis.y = -mEigenVectors(0, 1);
2809  hResult->vSecondAxis.z = -mEigenVectors(0, 2);
2810  }
2811 
2812 
2813  hResult->vThirdAxis.x = mEigenVectors(1, 0);
2814  hResult->vThirdAxis.y = mEigenVectors(1, 1);
2815  hResult->vThirdAxis.z = mEigenVectors(1, 2);
2816 
2817  Math3d::NormalizeVec(hResult->vNormal);
2818  Math3d::NormalizeVec(hResult->vSecondAxis);
2819  Math3d::NormalizeVec(hResult->vThirdAxis);
2820 
2821  hResult->fStdDev1 = mEigenValues(0, 0);
2822  hResult->fStdDev2 = mEigenValues(0, 1);
2823 
2824  hResult->fMaxExtent = 0;
2825  float fDist;
2826 
2827  for (int i = 0; i < nNum3dPoints; i++)
2828  {
2829  fDist = Math3d::Distance(hResult->vCenter, avPlanePoints[i]);
2830 
2831  if (fDist > hResult->fMaxExtent)
2832  {
2833  hResult->fMaxExtent = fDist;
2834  }
2835  }
2836 
2837 
2838  hResult->mLastRotation = Math3d::unit_mat;
2839  hResult->vLastTranslation = Math3d::zero_vec;
2840 
2841  return hResult;
2842 }
2843 
2846  const Vec3d vCylinderAxis,
2847  const Vec3d vCylinderCenter,
2848  const float fCylinderRadius,
2849  std::vector<CMSERDescriptor3D*>& aMSERs,
2850  std::vector<Vec3d>& aSigmaPoints,
2851  const CByteImage* pLeftColorImage,
2852  const CByteImage* pLeftGreyImage)
2853 {
2854  CObjectHypothesis* hResult = new CObjectHypothesis();
2855 
2857 
2858  const int nNum3dPoints = avCylinderPoints.GetSize();
2859 
2860 #pragma omp parallel
2861  {
2862  CHypothesisPoint* pPoint;
2863 
2864 #pragma omp for schedule(static, 5)
2865  for (int i = 0; i < nNum3dPoints; i++)
2866  {
2867  pPoint = new CHypothesisPoint();
2868 
2869  if (CreateFeatureDescriptorForPoint(pPoint,
2870  avCylinderPoints[i],
2871  aMSERs,
2872  aSigmaPoints,
2873  pLeftColorImage,
2874  pLeftGreyImage))
2875  {
2876 #pragma omp critical
2877  hResult->aNewPoints.push_back(pPoint);
2878  }
2879  else
2880  {
2881  delete pPoint;
2882  }
2883  }
2884  }
2885 
2886  // set axis and radius
2887  Math3d::SetVec(hResult->vCylinderAxis, vCylinderAxis);
2888  hResult->fRadius = fCylinderRadius;
2889 
2890  // calculate mean
2891  Vec3d vMean;
2892  const float fVariance = GetVariance(avCylinderPoints, vMean);
2893 
2894  // project the mean onto the axis
2895  // project point P onto the line given by point A and vector AB:
2896  // P' = A + ( AB*AP / |AB|^2 ) AB (here: |AB|=1)
2897  Vec3d vCenterOnAxis = vCylinderCenter;
2898  Vec3d vTemp1, vTemp2;
2899  Math3d::SubtractVecVec(vMean, vCylinderCenter, vTemp1);
2900  Math3d::MulVecScalar(vCylinderAxis, Math3d::ScalarProduct(vCylinderAxis, vTemp1), vTemp2);
2901  Math3d::AddToVec(vCenterOnAxis, vTemp2);
2902  Math3d::SetVec(hResult->vCenter, vCenterOnAxis);
2903 
2904  // normal is the vector from the center on the axis to the mean of the cylinder points
2905  Math3d::SubtractVecVec(vMean, vCenterOnAxis, hResult->vNormal);
2906  Math3d::NormalizeVec(hResult->vNormal);
2907 
2908 
2909  // first axis is cylinder axis, second is orthogonal to cylinder axis and surface normal,
2910  // third axis is surface normal
2911  Math3d::CrossProduct(vCylinderAxis, hResult->vNormal, hResult->vSecondAxis);
2912  Math3d::SetVec(hResult->vThirdAxis, hResult->vNormal);
2913 
2914 
2915  // simple solution
2916  hResult->fStdDev1 = fVariance;
2917  hResult->fStdDev2 = fVariance;
2918 
2919  hResult->fMaxExtent = hResult->fRadius;
2920  float fDist;
2921 
2922  for (int i = 0; i < nNum3dPoints; i++)
2923  {
2924  fDist = Math3d::Distance(hResult->vCenter, avCylinderPoints[i]);
2925 
2926  if (fDist > hResult->fMaxExtent)
2927  {
2928  hResult->fMaxExtent = fDist;
2929  }
2930  }
2931 
2932  hResult->mLastRotation = Math3d::unit_mat;
2933  hResult->vLastTranslation = Math3d::zero_vec;
2934 
2935  return hResult;
2936 }
2937 
2940  const Vec3d vSphereCenter,
2941  const float fSphereRadius,
2942  std::vector<CMSERDescriptor3D*>& aMSERs,
2943  std::vector<Vec3d>& aSigmaPoints,
2944  const CByteImage* pLeftColorImage,
2945  const CByteImage* pLeftGreyImage)
2946 {
2947  CObjectHypothesis* hResult = new CObjectHypothesis();
2948 
2949  hResult->eType = CObjectHypothesis::eSphere;
2950 
2951  const int nNum3dPoints = avSpherePoints.GetSize();
2952 
2953 #pragma omp parallel
2954  {
2955  CHypothesisPoint* pPoint;
2956 
2957 #pragma omp for schedule(static, 5)
2958  for (int i = 0; i < nNum3dPoints; i++)
2959  {
2960  if (CreateFeatureDescriptorForPoint(pPoint,
2961  avSpherePoints[i],
2962  aMSERs,
2963  aSigmaPoints,
2964  pLeftColorImage,
2965  pLeftGreyImage))
2966  {
2967 #pragma omp critical
2968  hResult->aNewPoints.push_back(pPoint);
2969  }
2970  else
2971  {
2972  delete pPoint;
2973  }
2974  }
2975  }
2976 
2977  // set center and radius
2978  Math3d::SetVec(hResult->vCenter, vSphereCenter);
2979  hResult->fRadius = fSphereRadius;
2980 
2981 
2982  // normal is the vector from the center to the mean of the sphere points
2983  Vec3d vMean;
2984  const float fVariance = GetVariance(avSpherePoints, vMean);
2985  Math3d::SubtractVecVec(vMean, vSphereCenter, hResult->vNormal);
2986  Math3d::NormalizeVec(hResult->vNormal);
2987 
2988 
2989  // second axis is orthogonal to normal and x axis, third axis orthogonal to normal and second
2990  Vec3d vXAxis = {1, 0, 0};
2991  Math3d::CrossProduct(hResult->vNormal, vXAxis, hResult->vSecondAxis);
2992  Math3d::CrossProduct(hResult->vNormal, hResult->vSecondAxis, hResult->vThirdAxis);
2993 
2994 
2995  // variances dont make much sense here...
2996  hResult->fStdDev1 = fVariance;
2997  hResult->fStdDev2 = fVariance;
2998 
2999  hResult->fMaxExtent = hResult->fRadius;
3000  float fDist;
3001 
3002  for (int i = 0; i < nNum3dPoints; i++)
3003  {
3004  fDist = Math3d::Distance(hResult->vCenter, avSpherePoints[i]);
3005 
3006  if (fDist > hResult->fMaxExtent)
3007  {
3008  hResult->fMaxExtent = fDist;
3009  }
3010  }
3011 
3012  hResult->mLastRotation = Math3d::unit_mat;
3013  hResult->vLastTranslation = Math3d::zero_vec;
3014 
3015  return hResult;
3016 }
3017 
3018 bool
3019 CHypothesisGeneration::CreateFeatureDescriptorForPoint(CHypothesisPoint* pPoint,
3020  Vec3d vPosition,
3021  std::vector<CMSERDescriptor3D*>& aMSERs,
3022  std::vector<Vec3d>& aSigmaPoints,
3023  const CByteImage* pLeftColorImage,
3024  const CByteImage* pLeftGreyImage)
3025 {
3026  pPoint->vPosition = vPosition;
3027  pPoint->vOldPosition = vPosition;
3028  pPoint->fMembershipProbability = 0.5f;
3029 
3030  // set color
3031  Vec2d vPos2d;
3032  calibration->WorldToImageCoordinates(vPosition, vPos2d, false);
3033  const int nIndexX = round(vPos2d.x);
3034  const int nIndexY = round(vPos2d.y);
3035 
3036  if (nIndexX < 0 || nIndexX > OLP_IMG_WIDTH - 1 || nIndexY < 0 || nIndexY > OLP_IMG_HEIGHT - 1)
3037  {
3038  return false;
3039  }
3040 
3041  const float fIntensity = pLeftColorImage->pixels[3 * (nIndexY * OLP_IMG_WIDTH + nIndexX)] +
3042  pLeftColorImage->pixels[3 * (nIndexY * OLP_IMG_WIDTH + nIndexX) + 1] +
3043  pLeftColorImage->pixels[3 * (nIndexY * OLP_IMG_WIDTH + nIndexX) + 2] +
3044  3;
3045  pPoint->fIntensity = (fIntensity - 3) / (3 * 255);
3046  pPoint->fColorR =
3047  (pLeftColorImage->pixels[3 * (nIndexY * OLP_IMG_WIDTH + nIndexX)] + 1) / fIntensity;
3048  pPoint->fColorG =
3049  (pLeftColorImage->pixels[3 * (nIndexY * OLP_IMG_WIDTH + nIndexX) + 1] + 1) / fIntensity;
3050  pPoint->fColorB =
3051  (pLeftColorImage->pixels[3 * (nIndexY * OLP_IMG_WIDTH + nIndexX) + 2] + 1) / fIntensity;
3052 
3053  // check if the point is the center of an MSER
3054  int nRegionIndex = FindRegionForPoint(vPosition, aMSERs);
3055 
3056  if (nRegionIndex >= 0)
3057  {
3058  // associate MSER descriptor with that point
3060  pPoint->pFeatureDescriptors = NULL;
3061  pPoint->pMSERDescriptor = aMSERs.at(nRegionIndex)->GetCopy();
3062  return true;
3063  }
3064 
3065  // check if it is a sigma point. if yes, ignore it
3066  if (PointIsInList(vPosition, aSigmaPoints))
3067  {
3068  return false;
3069  }
3070 
3071  // else create SIFT descriptor
3073  pPoint->pMSERDescriptor = NULL;
3074  pPoint->pFeatureDescriptors = new CSIFTFeatureArray();
3075  AddSIFTFeatureDescriptors(pPoint->pFeatureDescriptors, vPos2d, pLeftGreyImage);
3076 
3077  return true;
3078 }
3079 
3080 bool
3081 CHypothesisGeneration::RANSACPlane(const CVec3dArray& pointCandidates,
3082  const float fRANSACThreshold,
3083  const int nIterations,
3084  CVec3dArray& resultPoints,
3085  Vec3d& vAxis,
3086  float& d)
3087 {
3088  const int nPointCandidates = pointCandidates.GetSize();
3089 
3090  if (nPointCandidates < 3)
3091  {
3093  << "At least 3 point candidates must be provided for RANSAC::RANSAC3DPlane ("
3094  << nPointCandidates << " provided)";
3095  return false;
3096  }
3097 
3098  const int nParallelityFactor = omp_get_num_procs();
3099  omp_set_num_threads(nParallelityFactor);
3100 
3101  int* pMaxPar = new int[nParallelityFactor];
3102  float* pBestC = new float[nParallelityFactor];
3103  Vec3d* pBestN = new Vec3d[nParallelityFactor];
3104 
3105  for (int i = 0; i < nParallelityFactor; i++)
3106  {
3107  pMaxPar[i] = 0;
3108  pBestC[i] = 0;
3109  pBestN[i] = Math3d::zero_vec;
3110  }
3111 
3112 
3113 #pragma omp parallel
3114  {
3115  const int nProcIndex = omp_get_thread_num();
3116 
3117 #pragma omp for schedule(dynamic, 200)
3118  for (int i = 0; i < nIterations; i++)
3119  {
3120  // identify 3 different points
3121  srand((rand() % 17) * i + i);
3122  const int nFirstIndex = rand() % nPointCandidates;
3123 
3124  int nTempIndex;
3125 
3126  do
3127  {
3128  nTempIndex = rand() % nPointCandidates;
3129  } while (nTempIndex == nFirstIndex);
3130 
3131  const int nSecondIndex = nTempIndex;
3132 
3133  do
3134  {
3135  nTempIndex = rand() % nPointCandidates;
3136  } while (nTempIndex == nFirstIndex || nTempIndex == nSecondIndex);
3137 
3138  const Vec3d& p1 = pointCandidates[nFirstIndex];
3139  const Vec3d& p2 = pointCandidates[nSecondIndex];
3140  const Vec3d& p3 = pointCandidates[nTempIndex];
3141 
3142  Vec3d u1, u2, n;
3143  Math3d::SubtractVecVec(p2, p1, u1);
3144  Math3d::SubtractVecVec(p3, p1, u2);
3145  Math3d::CrossProduct(u1, u2, n);
3146  Math3d::NormalizeVec(n);
3147  const float c = Math3d::ScalarProduct(n, p1);
3148 
3149  // normal sometimes is (0,0,0), probably because of colinear points
3150  if (Math3d::ScalarProduct(n, n) < 0.9f)
3151  {
3152  continue;
3153  }
3154 
3155  // count support
3156  int nSupport = 0;
3157 
3158  for (int j = 0; j < nPointCandidates; j++)
3159  if (fabsf(Math3d::ScalarProduct(n, pointCandidates[j]) - c) <= fRANSACThreshold)
3160  {
3161  nSupport++;
3162  }
3163 
3164  // store if it is the current maximum
3165  if (nSupport > pMaxPar[nProcIndex])
3166  {
3167  pMaxPar[nProcIndex] = nSupport;
3168  Math3d::SetVec(pBestN[nProcIndex], n);
3169  pBestC[nProcIndex] = c;
3170  }
3171  }
3172  }
3173 
3174  int nMax = 0;
3175  float fBestC = 0;
3176  Vec3d vBestN = {0, 0, 0};
3177 
3178  for (int i = 0; i < nParallelityFactor; i++)
3179  {
3180  if (pMaxPar[i] > nMax)
3181  {
3182  nMax = pMaxPar[i];
3183  fBestC = pBestC[i];
3184  Math3d::SetVec(vBestN, pBestN[i]);
3185  }
3186  }
3187 
3188  // filter points
3189  resultPoints.Clear();
3190 
3191  for (int i = 0; i < nPointCandidates; i++)
3192  {
3193  if (fabsf(Math3d::ScalarProduct(pointCandidates[i], vBestN) - fBestC) <= fRANSACThreshold)
3194  {
3195  resultPoints.AddElement(pointCandidates[i]);
3196  }
3197  }
3198 
3199  Math3d::SetVec(vAxis, vBestN);
3200  d = fBestC;
3201 
3202  //ARMARX_VERBOSE_S << "plane: %d p\n", resultPoints.GetSize());
3203  delete[] pMaxPar;
3204  delete[] pBestC;
3205  delete[] pBestN;
3206 
3207  return true;
3208 }
3209 
3210 void
3211 CHypothesisGeneration::AddSIFTFeatureDescriptors(CSIFTFeatureArray* pFeatures,
3212  Vec2d vPoint2d,
3213  const CByteImage* pLeftGreyImage)
3214 {
3215  CDynamicArray afSIFTDescriptors(10);
3216  m_pSIFTFeatureCalculator->CreateSIFTDescriptors(
3217  pLeftGreyImage, &afSIFTDescriptors, vPoint2d.x, vPoint2d.y, 0.8f, false, true);
3218  m_pSIFTFeatureCalculator->CreateSIFTDescriptors(
3219  pLeftGreyImage, &afSIFTDescriptors, vPoint2d.x, vPoint2d.y, 1.0f, false, true);
3220  m_pSIFTFeatureCalculator->CreateSIFTDescriptors(
3221  pLeftGreyImage, &afSIFTDescriptors, vPoint2d.x, vPoint2d.y, 1.25f, false, true);
3222  const int n = afSIFTDescriptors.GetSize();
3223  CSIFTFeatureEntry** ppFeatures = new CSIFTFeatureEntry*[n];
3224 
3225  for (int i = 0; i < n; i++)
3226  {
3227  pFeatures->AddElement(
3228  (CSIFTFeatureEntry*)((CSIFTFeatureEntry*)afSIFTDescriptors[i])->Clone());
3229  afSIFTDescriptors[i]->bDelete = false;
3230  ppFeatures[i] = (CSIFTFeatureEntry*)afSIFTDescriptors[i];
3231  }
3232 
3233  afSIFTDescriptors.Clear();
3234 
3235  for (int i = 0; i < n; i++)
3236  {
3237  delete ppFeatures[i];
3238  }
3239 
3240  delete[] ppFeatures;
3241 }
3242 
3243 void
3244 CHypothesisGeneration::ClusterXMeans(const CVec3dArray& aPoints,
3245  const int nMaxNumClusters,
3246  const float fBICFactor,
3247  std::vector<CVec3dArray*>& aaPointClusters)
3248 {
3249  cv::Mat mSamples;
3250  cv::Mat mClusterLabels;
3251  cv::Mat pmClusterCenters; // = NULL;
3252  const int nNumberOfDifferentInitialisations = 5;
3253  cv::TermCriteria tTerminationCriteria(
3254  cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 50, 0.01);
3255 
3256  // copy the points
3257  const int nNumberOfSamples = aPoints.GetSize();
3258  mSamples.create(nNumberOfSamples, 3, CV_32FC1);
3259 
3260  for (int i = 0; i < nNumberOfSamples; i++)
3261  {
3262  mSamples.at<float>(i, 0) = aPoints[i].x;
3263  mSamples.at<float>(i, 1) = aPoints[i].y;
3264  mSamples.at<float>(i, 2) = aPoints[i].z;
3265  }
3266 
3267  mClusterLabels.create(nNumberOfSamples, 1, CV_32SC1);
3268 
3269  // execute k-means for several values of k and find the value for k that minimises the
3270  // Bayesian Information Criterion (BIC)
3271  Vec3d* pvClusterMeans = new Vec3d[nMaxNumClusters];
3272  double* pdClusterVariances = new double[nMaxNumClusters];
3273  int* pnClusterSizes = new int[nMaxNumClusters];
3274  double dMinBIC = 10000000;
3275  int nOptK = 1;
3276  double dKMeansCompactness, dLogVar, dBIC;
3277 
3278  for (int i = 1; (i <= nMaxNumClusters) && (i < nNumberOfSamples); i++)
3279  {
3280 #ifdef OLP_USE_NEW_OPENCV
3281  dKMeansCompactness = cv::kmeans(mSamples,
3282  i,
3283  mClusterLabels,
3284  tTerminationCriteria,
3285  nNumberOfDifferentInitialisations,
3286  cv::KMEANS_RANDOM_CENTERS,
3287  pmClusterCenters);
3288 #else
3289  //dKMeansCompactness = cv::kmeans(mSamples, i, mClusterLabels, tTerminationCriteria, nNumberOfDifferentInitialisations, cv::KMEANS_RANDOM_CENTERS, &pmClusterCenters);
3290  dKMeansCompactness = cv::kmeans(mSamples,
3291  i,
3292  mClusterLabels,
3293  tTerminationCriteria,
3294  nNumberOfDifferentInitialisations,
3295  cv::KMEANS_PP_CENTERS,
3296  &pmClusterCenters);
3297 #endif
3298 
3299  //const double dMLVariance = 1/(double)(nNumberOfSamples-i) * dKMeansCompactness;
3300 
3301  // calculate variances of the clusters
3302  double dMLVariance = 0;
3303 
3304  for (int j = 0; j < i; j++)
3305  {
3306  pvClusterMeans[j].x = 0;
3307  pvClusterMeans[j].y = 0;
3308  pvClusterMeans[j].z = 0;
3309  pdClusterVariances[j] = 0;
3310  pnClusterSizes[j] = 0;
3311 
3312  for (int l = 0; l < nNumberOfSamples; l++)
3313  {
3314  if (mClusterLabels.at<int>(l, 0) == j)
3315  {
3316  pvClusterMeans[j].x += mSamples.at<float>(l, 0);
3317  pvClusterMeans[j].y += mSamples.at<float>(l, 1);
3318  pvClusterMeans[j].z += mSamples.at<float>(l, 2);
3319  pnClusterSizes[j]++;
3320  }
3321  }
3322 
3323  pvClusterMeans[j].x /= (float)pnClusterSizes[j];
3324  pvClusterMeans[j].y /= (float)pnClusterSizes[j];
3325  pvClusterMeans[j].z /= (float)pnClusterSizes[j];
3326 
3327  for (int l = 0; l < nNumberOfSamples; l++)
3328  {
3329  if (mClusterLabels.at<int>(l, 0) == j)
3330  {
3331  pdClusterVariances[j] += (pvClusterMeans[j].x - mSamples.at<float>(l, 0)) *
3332  (pvClusterMeans[j].x - mSamples.at<float>(l, 0)) +
3333  (pvClusterMeans[j].y - mSamples.at<float>(l, 1)) *
3334  (pvClusterMeans[j].x - mSamples.at<float>(l, 1)) +
3335  (pvClusterMeans[j].z - mSamples.at<float>(l, 2)) *
3336  (pvClusterMeans[j].x - mSamples.at<float>(l, 2));
3337  }
3338  }
3339 
3340  if (pnClusterSizes[j] > 1)
3341  {
3342  pdClusterVariances[j] /= (float)(pnClusterSizes[j] - 1);
3343  }
3344  else
3345  {
3346  pdClusterVariances[j] = 0;
3347  }
3348 
3349  dMLVariance += pdClusterVariances[j];
3350  //ARMARX_VERBOSE_S << "pnClusterSizes[%d] = %d \n", j, pnClusterSizes[j]);
3351  }
3352 
3353  const int nNumberOfFreeParameters = (i - 1) + (3 * i) + i;
3354  dLogVar = log(dMLVariance);
3355  dBIC = fBICFactor * 0.35 * dLogVar +
3356  ((double)nNumberOfFreeParameters / (double)nNumberOfSamples) *
3357  log((double)nNumberOfSamples); // 0.4 // 1.5 with manual variance
3358 
3359  if (dBIC < dMinBIC)
3360  {
3361  dMinBIC = dBIC;
3362  nOptK = i;
3363  }
3364 
3365  //ARMARX_VERBOSE_S << "k-means with %d clusters. log(var): %.3f BIC: %.3f\n", i, dLogVar, dBIC);
3366  }
3367 
3368  // execute k-means with optimal k
3369  if (nOptK > 1)
3370  {
3371 #ifdef OLP_USE_NEW_OPENCV
3372  dKMeansCompactness = cv::kmeans(mSamples,
3373  nOptK,
3374  mClusterLabels,
3375  tTerminationCriteria,
3376  nNumberOfDifferentInitialisations,
3377  cv::KMEANS_RANDOM_CENTERS,
3378  pmClusterCenters);
3379 #else
3380  //dKMeansCompactness = cv::kmeans(mSamples, nOptK, mClusterLabels, tTerminationCriteria, nNumberOfDifferentInitialisations, cv::KMEANS_RANDOM_CENTERS, &pmClusterCenters);
3381  dKMeansCompactness = cv::kmeans(mSamples,
3382  nOptK,
3383  mClusterLabels,
3384  tTerminationCriteria,
3385  nNumberOfDifferentInitialisations,
3386  cv::KMEANS_PP_CENTERS,
3387  &pmClusterCenters);
3388 #endif
3389 
3390  //// get sizes of the clusters
3391  //int* pnClusterSizes = new int[nOptK];
3392  //for (int i=0; i<nOptK; i++) pnClusterSizes[i] = 0;
3393  //for (int i=0; i<nNumberOfSamples; i++)
3394  //{
3395  // if ( (mClusterLabels.at<int>(i,0) >=0) && (mClusterLabels.at<int>(i,0)<nOptK) )
3396  // {
3397  // pnClusterSizes[mClusterLabels.at<int>(i,0)]++;
3398  // }
3399  // else
3400  // {
3401  // ARMARX_VERBOSE_S << "\ninvalid cluster label: %d\n\n", mClusterLabels.at<int>(i,0));
3402  // ARMARX_VERBOSE_S << "\n");
3403  // }
3404  //}
3405 
3406 
3407  // copy the points belonging to the clusters
3408  Vec3d vPoint;
3409  aaPointClusters.clear();
3410  CVec3dArray* paDummy;
3411 
3412  for (int i = 0; i < nOptK; i++)
3413  {
3414  paDummy = new CVec3dArray();
3415  aaPointClusters.push_back(paDummy);
3416  }
3417 
3418  for (int i = 0; i < nNumberOfSamples; i++)
3419  {
3420  if ((mClusterLabels.at<int>(i, 0) >= 0) && (mClusterLabels.at<int>(i, 0) < nOptK))
3421  {
3422  vPoint.x = mSamples.at<float>(i, 0);
3423  vPoint.y = mSamples.at<float>(i, 1);
3424  vPoint.z = mSamples.at<float>(i, 2);
3425  aaPointClusters.at(mClusterLabels.at<int>(i, 0))->AddElement(vPoint);
3426  }
3427  else
3428  {
3429  ARMARX_WARNING_S << "Invalid cluster label: " << mClusterLabels.at<int>(i, 0)
3430  << "nOptK: " << nOptK << ", i: " << i
3431  << ", nNumberOfSamples: " << nNumberOfSamples
3432  << ", dKMeansCompactness: " << dKMeansCompactness;
3433  break;
3434  }
3435  }
3436  }
3437  else
3438  {
3439  aaPointClusters.clear();
3440  CVec3dArray* paDummy = new CVec3dArray();
3441  aaPointClusters.push_back(paDummy);
3442  Vec3d vPoint;
3443 
3444  for (int i = 0; i < nNumberOfSamples; i++)
3445  {
3446  vPoint.x = mSamples.at<float>(i, 0);
3447  vPoint.y = mSamples.at<float>(i, 1);
3448  vPoint.z = mSamples.at<float>(i, 2);
3449  aaPointClusters.at(0)->AddElement(vPoint);
3450  }
3451  }
3452 
3453  //delete pmClusterCenters;
3454  delete[] pvClusterMeans;
3455  delete[] pdClusterVariances;
3456  delete[] pnClusterSizes;
3457 }
3458 
3459 inline void
3460 CHypothesisGeneration::SortMSERsBySize(std::vector<CMSERDescriptor3D*>& aRegions3D)
3461 {
3462  // insertion sort
3463  CMSERDescriptor3D* pTemp;
3464 
3465  for (int i = 1; i < (int)aRegions3D.size(); i++)
3466  {
3467  pTemp = aRegions3D.at(i);
3468  int j = i;
3469 
3470  while ((j > 0) && (aRegions3D.at(j - 1)->pRegionLeft->nSize < pTemp->pRegionLeft->nSize))
3471  {
3472  aRegions3D.at(j) = aRegions3D.at(j - 1);
3473  j--;
3474  }
3475 
3476  aRegions3D.at(j) = pTemp;
3477  }
3478 }
3479 
3480 inline void
3481 CHypothesisGeneration::SortMSERsByX(std::vector<CMSERDescriptor3D*>& aRegions3D)
3482 {
3483  // insertion sort
3484  CMSERDescriptor3D* pTemp;
3485 
3486  for (int i = 1; i < (int)aRegions3D.size(); i++)
3487  {
3488  pTemp = aRegions3D.at(i);
3489  int j = i;
3490 
3491  while ((j > 0) && (aRegions3D.at(j - 1)->vPosition.x > pTemp->vPosition.x))
3492  {
3493  aRegions3D.at(j) = aRegions3D.at(j - 1);
3494  j--;
3495  }
3496 
3497  aRegions3D.at(j) = pTemp;
3498  }
3499 }
3500 
3501 inline int
3502 CHypothesisGeneration::FindRegionForPoint(Vec3d vPoint, std::vector<CMSERDescriptor3D*>& aRegions3D)
3503 {
3504  // binary search
3505  int nLeft = 0;
3506  int nRight = (int)aRegions3D.size() - 1;
3507  int nIndex, i;
3508 
3509  while (nRight > nLeft + 1)
3510  {
3511  nIndex = nLeft + ((nRight - nLeft) >> 1);
3512 
3513  if (vPoint.x < aRegions3D.at(nIndex)->vPosition.x)
3514  {
3515  nRight = nIndex;
3516  }
3517  else if (vPoint.x > aRegions3D.at(nIndex)->vPosition.x)
3518  {
3519  nLeft = nIndex;
3520  }
3521  else // we got the right x value
3522  {
3523  // search to the left
3524  i = nIndex;
3525 
3526  while ((i >= nLeft) && (vPoint.x == aRegions3D.at(i)->vPosition.x))
3527  {
3528  if ((vPoint.y == aRegions3D.at(i)->vPosition.y) &&
3529  (vPoint.z == aRegions3D.at(i)->vPosition.z))
3530  {
3531  return i;
3532  }
3533  else
3534  {
3535  i--;
3536  }
3537  }
3538 
3539  // search to the right
3540  i = nIndex + 1;
3541 
3542  while ((i <= nRight) && (vPoint.x == aRegions3D.at(i)->vPosition.x))
3543  {
3544  if ((vPoint.y == aRegions3D.at(i)->vPosition.y) &&
3545  (vPoint.z == aRegions3D.at(i)->vPosition.z))
3546  {
3547  return i;
3548  }
3549  else
3550  {
3551  i++;
3552  }
3553  }
3554 
3555  return -1;
3556  }
3557  }
3558 
3559  if (nLeft <= nRight)
3560  {
3561  if ((vPoint.x == aRegions3D.at(nLeft)->vPosition.x) &&
3562  (vPoint.y == aRegions3D.at(nLeft)->vPosition.y) &&
3563  (vPoint.z == aRegions3D.at(nLeft)->vPosition.z))
3564  {
3565  return nLeft;
3566  }
3567  else if ((vPoint.x == aRegions3D.at(nRight)->vPosition.x) &&
3568  (vPoint.y == aRegions3D.at(nRight)->vPosition.y) &&
3569  (vPoint.z == aRegions3D.at(nRight)->vPosition.z))
3570  {
3571  return nRight;
3572  }
3573  }
3574 
3575  return -1;
3576 }
3577 
3578 inline void
3579 CHypothesisGeneration::SortVec3dsByX(std::vector<Vec3d>& aPoints)
3580 {
3581  // insertion sort
3582  Vec3d vTemp;
3583 
3584  for (int i = 1; i < (int)aPoints.size(); i++)
3585  {
3586  Math3d::SetVec(vTemp, aPoints.at(i));
3587  int j = i;
3588 
3589  while ((j > 0) && (aPoints.at(j - 1).x > vTemp.x))
3590  {
3591  Math3d::SetVec(aPoints.at(j), aPoints.at(j - 1));
3592  j--;
3593  }
3594 
3595  Math3d::SetVec(aPoints.at(j), vTemp);
3596  }
3597 }
3598 
3599 inline bool
3600 CHypothesisGeneration::PointIsInList(Vec3d vPoint, std::vector<Vec3d>& aPoints)
3601 {
3602  // binary search
3603  int nLeft = 0;
3604  int nRight = (int)aPoints.size() - 1;
3605  int nIndex;
3606 
3607  while (nRight > nLeft + 1)
3608  {
3609  nIndex = nLeft + ((nRight - nLeft) >> 1);
3610 
3611  if (vPoint.x < aPoints.at(nIndex).x)
3612  {
3613  nRight = nIndex;
3614  }
3615  else if (vPoint.x > aPoints.at(nIndex).x)
3616  {
3617  nLeft = nIndex;
3618  }
3619  else if ((vPoint.y == aPoints.at(nIndex).y) && (vPoint.z == aPoints.at(nIndex).z))
3620  {
3621  return true;
3622  }
3623  else
3624  {
3625  nLeft++; // ugly, incorrect and easy
3626  }
3627  }
3628 
3629  if (nLeft <= nRight)
3630  {
3631  if ((vPoint.x == aPoints.at(nLeft).x) && (vPoint.y == aPoints.at(nLeft).y) &&
3632  (vPoint.z == aPoints.at(nLeft).z))
3633  {
3634  return true;
3635  }
3636  else if ((vPoint.x == aPoints.at(nRight).x) && (vPoint.y == aPoints.at(nRight).y) &&
3637  (vPoint.z == aPoints.at(nRight).z))
3638  {
3639  return true;
3640  }
3641  }
3642 
3643  return false;
3644 }
3645 
3646 void
3647 CHypothesisGeneration::CalculateSphere(Vec3d vPoint1,
3648  Vec3d vPoint2,
3649  Vec3d vPoint3,
3650  Vec3d vPoint4,
3651  Vec3d& vCenter,
3652  float& fRadius)
3653 {
3654 
3655  /*
3656  // matrix containing in each row
3657  // x^2+y^2+z^2 x y z 1
3658  // first row unknown variables, second row first point, third row second point etc
3659  float pMatrix[25];
3660 
3661  // first row is unknown and will not be used
3662  //pMatrix[0] = 0;
3663  //pMatrix[1] = 0;
3664  //pMatrix[2] = 0;
3665  //pMatrix[3] = 0;
3666  //pMatrix[4] = 0;
3667 
3668  // first point
3669  pMatrix[5] = vPoint1.x*vPoint1.x + vPoint1.y*vPoint1.y + vPoint1.z*vPoint1.z;
3670  pMatrix[6] = vPoint1.x;
3671  pMatrix[7] = vPoint1.y;
3672  pMatrix[8] = vPoint1.z;
3673  pMatrix[9] = 1;
3674 
3675  // second point
3676  pMatrix[10] = vPoint2.x*vPoint2.x + vPoint2.y*vPoint2.y + vPoint2.z*vPoint2.z;
3677  pMatrix[11] = vPoint2.x;
3678  pMatrix[12] = vPoint2.y;
3679  pMatrix[13] = vPoint2.z;
3680  pMatrix[14] = 1;
3681 
3682  pMatrix[15] = vPoint3.x*vPoint3.x + vPoint3.y*vPoint3.y + vPoint3.z*vPoint3.z;
3683  pMatrix[16] = vPoint3.x;
3684  pMatrix[17] = vPoint3.y;
3685  pMatrix[18] = vPoint3.z;
3686  pMatrix[19] = 1;
3687 
3688  pMatrix[20] = vPoint4.x*vPoint4.x + vPoint4.y*vPoint4.y + vPoint4.z*vPoint4.z;
3689  pMatrix[21] = vPoint4.x;
3690  pMatrix[22] = vPoint4.y;
3691  pMatrix[23] = vPoint4.z;
3692  pMatrix[24] = 1;
3693  */
3694 
3695  // submatrix M_ij: matrix that consists of what is left of M when deleting row i and column j
3696  float pSubmatrix[16];
3697 
3698  // determinants of the submatrices
3699  float fDetM11, fDetM12, fDetM13, fDetM14, fDetM15;
3700  /*
3701  int nIgnoreColumn, l;
3702 
3703  nIgnoreColumn = 0;
3704  for (int i=1; i<5; i++)
3705  {
3706  l = 0;
3707  for (int j=0; j<5; j++)
3708  {
3709  if (j != nIgnoreColumn)
3710  {
3711  pSubmatrix[4*(i-1)+l] = pMatrix[5*i+j];
3712  l++;
3713  }
3714  }
3715  }
3716  fDetM11 = Determinant4x4(pSubmatrix);
3717 
3718  if (fDetM11==0)
3719  {
3720  vCenter.x = 0;
3721  vCenter.y = 0;
3722  vCenter.z = 0;
3723  fRadius = 0;
3724  return;
3725  }
3726 
3727  nIgnoreColumn = 1;
3728  for (int i=1; i<5; i++)
3729  {
3730  l = 0;
3731  for (int j=0; j<5; j++)
3732  {
3733  if (j != nIgnoreColumn)
3734  {
3735  pSubmatrix[4*(i-1)+l] = pMatrix[5*i+j];
3736  l++;
3737  }
3738  }
3739  }
3740  fDetM12 = Determinant4x4(pSubmatrix);
3741 
3742  nIgnoreColumn = 2;
3743  for (int i=1; i<5; i++)
3744  {
3745  l = 0;
3746  for (int j=0; j<5; j++)
3747  {
3748  if (j != nIgnoreColumn)
3749  {
3750  pSubmatrix[4*(i-1)+l] = pMatrix[5*i+j];
3751  l++;
3752  }
3753  }
3754  }
3755  fDetM13 = Determinant4x4(pSubmatrix);
3756 
3757  nIgnoreColumn = 3;
3758  for (int i=1; i<5; i++)
3759  {
3760  l = 0;
3761  for (int j=0; j<5; j++)
3762  {
3763  if (j != nIgnoreColumn)
3764  {
3765  pSubmatrix[4*(i-1)+l] = pMatrix[5*i+j];
3766  l++;
3767  }
3768  }
3769  }
3770  fDetM14 = Determinant4x4(pSubmatrix);
3771 
3772  nIgnoreColumn = 4;
3773  for (int i=1; i<5; i++)
3774  {
3775  l = 0;
3776  for (int j=0; j<5; j++)
3777  {
3778  if (j != nIgnoreColumn)
3779  {
3780  pSubmatrix[4*(i-1)+l] = pMatrix[5*i+j];
3781  l++;
3782  }
3783  }
3784  }
3785  fDetM15 = Determinant4x4(pSubmatrix);
3786  */
3787 
3788 
3789  Vec3d pPoints[4];
3790  Math3d::SetVec(pPoints[0], vPoint1);
3791  Math3d::SetVec(pPoints[1], vPoint2);
3792  Math3d::SetVec(pPoints[2], vPoint3);
3793  Math3d::SetVec(pPoints[3], vPoint4);
3794 
3795  // Find determinant M11
3796  for (int i = 0; i < 4; i++)
3797  {
3798  pSubmatrix[4 * i + 0] = pPoints[i].x;
3799  pSubmatrix[4 * i + 1] = pPoints[i].y;
3800  pSubmatrix[4 * i + 2] = pPoints[i].z;
3801  pSubmatrix[4 * i + 3] = 1;
3802  }
3803 
3804  fDetM11 = Determinant4x4(pSubmatrix);
3805 
3806  // Find determinant M12
3807  for (int i = 0; i < 4; i++)
3808  {
3809  pSubmatrix[4 * i + 0] =
3810  pPoints[i].x * pPoints[i].x + pPoints[i].y * pPoints[i].y + pPoints[i].z * pPoints[i].z;
3811  pSubmatrix[4 * i + 1] = pPoints[i].y;
3812  pSubmatrix[4 * i + 2] = pPoints[i].z;
3813  pSubmatrix[4 * i + 3] = 1;
3814  }
3815 
3816  fDetM12 = Determinant4x4(pSubmatrix);
3817 
3818  // Find determinant M13
3819  for (int i = 0; i < 4; i++)
3820  {
3821  pSubmatrix[4 * i + 0] = pPoints[i].x;
3822  pSubmatrix[4 * i + 1] =
3823  pPoints[i].x * pPoints[i].x + pPoints[i].y * pPoints[i].y + pPoints[i].z * pPoints[i].z;
3824  pSubmatrix[4 * i + 2] = pPoints[i].z;
3825  pSubmatrix[4 * i + 3] = 1;
3826  }
3827 
3828  fDetM13 = Determinant4x4(pSubmatrix);
3829 
3830  // Find determinant M14
3831  for (int i = 0; i < 4; i++)
3832  {
3833  pSubmatrix[4 * i + 0] = pPoints[i].x;
3834  pSubmatrix[4 * i + 1] = pPoints[i].y;
3835  pSubmatrix[4 * i + 2] =
3836  pPoints[i].x * pPoints[i].x + pPoints[i].y * pPoints[i].y + pPoints[i].z * pPoints[i].z;
3837  pSubmatrix[4 * i + 3] = 1;
3838  }
3839 
3840  fDetM14 = Determinant4x4(pSubmatrix);
3841 
3842  // Find determinant M15
3843  for (int i = 0; i < 4; i++)
3844  {
3845  pSubmatrix[4 * i + 0] =
3846  pPoints[i].x * pPoints[i].x + pPoints[i].y * pPoints[i].y + pPoints[i].z * pPoints[i].z;
3847  pSubmatrix[4 * i + 1] = pPoints[i].x;
3848  pSubmatrix[4 * i + 2] = pPoints[i].y;
3849  pSubmatrix[4 * i + 3] = pPoints[i].z;
3850  }
3851 
3852  fDetM15 = Determinant4x4(pSubmatrix);
3853 
3854 
3855  //ARMARX_VERBOSE_S << "M11: %.2f, M12: %.2f, M13: %.2f, M14: %.2f, M15: %.2f\n", fDetM11, fDetM12, fDetM13, fDetM14, fDetM15);
3856 
3857  vCenter.x = 0.5f * fDetM12 / fDetM11;
3858  vCenter.y = -0.5f * fDetM13 / fDetM11;
3859  vCenter.z = 0.5f * fDetM14 / fDetM11;
3860  fRadius = sqrtf(vCenter.x * vCenter.x + vCenter.y * vCenter.y + vCenter.z * vCenter.z -
3861  fDetM15 / fDetM11);
3862 }
3863 
3864 float
3866 {
3867  float fRet = 0;
3868  float fDet;
3869  float pSubMat[9];
3870 
3871  for (int n = 0; n < 4; n++)
3872  {
3873  // calculate the n-th subdeterminant, develop first row
3874  for (int i = 0; i < 3; i++)
3875  {
3876  for (int j = 0, l = 0; j < 4; j++)
3877  {
3878  if (j != n)
3879  {
3880  pSubMat[3 * i + l] = pMatrix[4 * (i + 1) + j];
3881  l++;
3882  }
3883  }
3884  }
3885 
3886  fDet = pSubMat[0] * pSubMat[4] * pSubMat[8] + pSubMat[1] * pSubMat[5] * pSubMat[6] +
3887  pSubMat[2] * pSubMat[3] * pSubMat[7] - pSubMat[2] * pSubMat[4] * pSubMat[6] -
3888  pSubMat[1] * pSubMat[3] * pSubMat[8] - pSubMat[0] * pSubMat[5] * pSubMat[7];
3889 
3890  if ((n == 0) || (n == 2))
3891  {
3892  fRet += pMatrix[n] * fDet;
3893  }
3894  else
3895  {
3896  fRet -= pMatrix[n] * fDet;
3897  }
3898  }
3899 
3900  return fRet;
3901 }
3902 
3903 bool
3904 CHypothesisGeneration::RANSACSphere(const CVec3dArray& aPointCandidates,
3905  const float fRANSACThreshold,
3906  const float fMaxSphereRadius,
3907  const int nMaxIterations,
3908  CVec3dArray& aResultPoints,
3909  Vec3d& vCenter,
3910  float& fRadius)
3911 {
3912  const int nPointCandidates = aPointCandidates.GetSize();
3913 
3914  aResultPoints.Clear();
3915 
3916  if (nPointCandidates < 4)
3917  {
3918  ARMARX_WARNING_S << "At least 4 point candidates must be provided for RANSAC for sphere ("
3919  << nPointCandidates << " provided)";
3920  return false;
3921  }
3922 
3923  int nMaxSupport = 0;
3924  Vec3d vBestCenter;
3925  float fBestRadius;
3926 
3927  int nTemp = (int)(OLP_EFFORT_MODIFICATOR * (nPointCandidates * nPointCandidates + 500));
3928 
3929  const int nIterations = (nTemp > nMaxIterations) ? nMaxIterations : nTemp;
3930 
3931 #pragma omp parallel
3932  {
3933 #pragma omp for schedule(static, 40)
3934  for (int i = 0; i < nIterations; i++)
3935  {
3936  // identify 4 different points
3937  srand((rand() % 17) * i + i);
3938  int nTempIndex;
3939  const int nFirstIndex = rand() % nPointCandidates;
3940 
3941  do
3942  {
3943  nTempIndex = rand() % nPointCandidates;
3944  } while (nTempIndex == nFirstIndex);
3945 
3946  const int nSecondIndex = nTempIndex;
3947 
3948  do
3949  {
3950  nTempIndex = rand() % nPointCandidates;
3951  } while (nTempIndex == nFirstIndex || nTempIndex == nSecondIndex);
3952 
3953  const int nThirdIndex = nTempIndex;
3954 
3955  do
3956  {
3957  nTempIndex = rand() % nPointCandidates;
3958  } while (nTempIndex == nFirstIndex || nTempIndex == nSecondIndex ||
3959  nTempIndex == nThirdIndex);
3960 
3961  const Vec3d& p1 = aPointCandidates[nFirstIndex];
3962  const Vec3d& p2 = aPointCandidates[nSecondIndex];
3963  const Vec3d& p3 = aPointCandidates[nThirdIndex];
3964  const Vec3d& p4 = aPointCandidates[nTempIndex];
3965 
3966  //Vec3d p1, p2, p3, p4;
3967  //p1.x = 1;
3968  //p1.y = 0;
3969  //p1.z = 0;
3970  //p2.x = -1;
3971  //p2.y = 0;
3972  //p2.z = 0;
3973  //p3.x = 0;
3974  //p3.y = 1;
3975  //p3.z = 0;
3976  //p4.x = 0;
3977  //p4.y = 0;
3978  //p4.z = 1;
3979 
3980  Vec3d vTempCenter;
3981  float fTempRadius;
3982 
3983  CalculateSphere(p1, p2, p3, p4, vTempCenter, fTempRadius);
3984 
3985  // if points lie on a plane or three of them on a line, they do not define a valid sphere
3986  if (fTempRadius == 0)
3987  {
3988  continue;
3989  }
3990 
3991  // only accept realistic values
3992  if ((fTempRadius > 100) || (vTempCenter.z < 100))
3993  {
3994  continue;
3995  }
3996 
3997  // count support
3998  int nSupport = 0;
3999 
4000  for (int j = 0; j < nPointCandidates; j++)
4001  {
4002  if (fabsf(Math3d::Distance(vTempCenter, aPointCandidates[j]) - fTempRadius) <=
4003  fRANSACThreshold)
4004  {
4005  nSupport++;
4006  }
4007  }
4008 
4009  //ARMARX_VERBOSE_S << "\n(%.1f, %.1f, %.1f) \t (%.1f, %.1f, %.1f) \n(%.1f, %.1f, %.1f) \t (%.1f, %.1f, %.1f)\n", p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, p4.x, p4.y, p4.z);
4010  //ARMARX_VERBOSE_S << "center: (%.1f, %.1f, %.1f) radius: %.1f support: %d\n", vTempCenter.x, vTempCenter.y, vTempCenter.z, fTempRadius, nSupport);
4011 
4012  // store if it is the current maximum
4013  if (nSupport > nMaxSupport)
4014  {
4015 #pragma omp critical
4016  if (nSupport > nMaxSupport)
4017  {
4018  nMaxSupport = nSupport;
4019  Math3d::SetVec(vBestCenter, vTempCenter);
4020  fBestRadius = fTempRadius;
4021  }
4022  }
4023  }
4024  }
4025 
4026  if (nMaxSupport < 4)
4027  {
4028  return false;
4029  }
4030 
4031  for (int i = 0; i < nPointCandidates; i++)
4032  {
4033  if (fabsf(Math3d::Distance(vBestCenter, aPointCandidates[i]) - fBestRadius) <=
4034  fRANSACThreshold)
4035  {
4036  aResultPoints.AddElement(aPointCandidates[i]);
4037  }
4038  }
4039 
4040  Math3d::SetVec(vCenter, vBestCenter);
4041  fRadius = fBestRadius;
4042 
4043  return true;
4044 }
CHypothesisPoint::eMSER
@ eMSER
Definition: ObjectHypothesis.h:231
HypothesisGeneration.h
CObjectHypothesis::eSphere
@ eSphere
Definition: ObjectHypothesis.h:284
OLP_IMG_HEIGHT
#define OLP_IMG_HEIGHT
Definition: ObjectLearningByPushingDefinitions.h:69
GfxTL::Vec3d
VectorXD< 3, double > Vec3d
Definition: VectorXD.h:737
OLP_MSER_HYPOTHESIS_MAX_SIZE
#define OLP_MSER_HYPOTHESIS_MAX_SIZE
Definition: ObjectLearningByPushingDefinitions.h:287
OLP_IMG_WIDTH
#define OLP_IMG_WIDTH
Definition: ObjectLearningByPushingDefinitions.h:68
CHypothesisPoint::pMSERDescriptor
CMSERDescriptor3D * pMSERDescriptor
Definition: ObjectHypothesis.h:241
COLPTools::CreateObjectSegmentationMask
void CreateObjectSegmentationMask(const CObjectHypothesis *pHypothesis, const CCalibration *calibration, CByteImage *&pForegroundImage)
Definition: OLPTools.cpp:1323
CHypothesisPoint::vOldPosition
Vec3d vOldPosition
Definition: ObjectHypothesis.h:236
OLP_DEPTH_MAP_PIXEL_DISTANCE
#define OLP_DEPTH_MAP_PIXEL_DISTANCE
Definition: ObjectLearningByPushingDefinitions.h:269
CSIFTFeatureArray
CDynamicArrayTemplate< CSIFTFeatureEntry * > CSIFTFeatureArray
Definition: ObjectHypothesis.h:164
CHypothesisPoint::fIntensity
float fIntensity
Definition: ObjectHypothesis.h:238
OLP_MSER_HYPOTHESIS_MIN_SIZE
#define OLP_MSER_HYPOTHESIS_MIN_SIZE
Definition: ObjectLearningByPushingDefinitions.h:285
OLP_MAX_NUM_CLUSTERING_PARTS
#define OLP_MAX_NUM_CLUSTERING_PARTS
Definition: ObjectLearningByPushingDefinitions.h:118
COLPTools::SetNumberInFileName
void SetNumberInFileName(std::string &sFileName, int nNumber, int nNumDigits)
Definition: OLPTools.cpp:1464
OLP_CLUSTERING_FACTOR_PLANES
#define OLP_CLUSTERING_FACTOR_PLANES
Definition: ObjectLearningByPushingDefinitions.h:116
CObjectHypothesis::fRadius
float fRadius
Definition: ObjectHypothesis.h:317
CHypothesisPoint::eHarrisCornerPoint
@ eHarrisCornerPoint
Definition: ObjectHypothesis.h:230
CHypothesisGeneration::CreateCylinderHypothesisDescriptor
CObjectHypothesis * CreateCylinderHypothesisDescriptor(const CVec3dArray &avCylinderPoints, const Vec3d vCylinderAxis, const Vec3d vCylinderCenter, const float fCylinderRadius, std::vector< CMSERDescriptor3D * > &aMSERs, std::vector< Vec3d > &aSigmaPoints, const CByteImage *pLeftColorImage, const CByteImage *pLeftGreyImage)
Definition: HypothesisGeneration.cpp:2845
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
CHypothesisGeneration::CreateSphereHypothesisDescriptor
CObjectHypothesis * CreateSphereHypothesisDescriptor(const CVec3dArray &avSpherePoints, const Vec3d vSphereCenter, const float fSphereRadius, std::vector< CMSERDescriptor3D * > &aMSERs, std::vector< Vec3d > &aSigmaPoints, const CByteImage *pLeftColorImage, const CByteImage *pLeftGreyImage)
Definition: HypothesisGeneration.cpp:2939
CObjectHypothesis::eType
eObjectType eType
Definition: ObjectHypothesis.h:292
CHypothesisPoint::fColorG
float fColorG
Definition: ObjectHypothesis.h:238
CObjectHypothesis::vThirdAxis
Vec3d vThirdAxis
Definition: ObjectHypothesis.h:308
CHypothesisGeneration::~CHypothesisGeneration
~CHypothesisGeneration(void)
Definition: HypothesisGeneration.cpp:87
CHypothesisPoint::vPosition
Vec3d vPosition
Definition: ObjectHypothesis.h:235
CMSERDescriptor3D::vPosition
Vec3d vPosition
Definition: ObjectHypothesis.h:156
CHypothesisGeneration::FindObjectHypotheses
void FindObjectHypotheses(CByteImage *pImageLeftColor, CByteImage *pImageRightColor, CByteImage *pImageLeftGrey, CByteImage *pImageRightGrey, CSIFTFeatureArray &aAllSIFTPoints, std::vector< CMSERDescriptor3D * > &aAllMSERs, std::vector< CHypothesisPoint * > &aPointsFromDisparity, CObjectHypothesisArray &aObjectHypotheses)
Definition: HypothesisGeneration.cpp:106
CSaliencyCalculation::FindSalientRegionsAchanta
void FindSalientRegionsAchanta(const CByteImage *pImageRGB, CByteImage *pSaliencyImage)
Definition: SaliencyCalculation.cpp:603
CObjectHypothesis::eRGBD
@ eRGBD
Definition: ObjectHypothesis.h:287
OLP_TOLERANCE_MODIFICATOR
#define OLP_TOLERANCE_MODIFICATOR
Definition: ObjectLearningByPushingDefinitions.h:99
OLP_MAX_NUM_HYPOTHESES
#define OLP_MAX_NUM_HYPOTHESES
Definition: ObjectLearningByPushingDefinitions.h:112
OLPTools.h
CHypothesisPoint
Definition: ObjectHypothesis.h:166
OLP_MIN_NUM_FEATURES
#define OLP_MIN_NUM_FEATURES
Definition: ObjectLearningByPushingDefinitions.h:109
CObjectHypothesis::vLastTranslation
Vec3d vLastTranslation
Definition: ObjectHypothesis.h:322
CMSERDescriptor3D
Definition: ObjectHypothesis.h:94
OLP_TOLERANCE_CONCURRENT_MOTION
#define OLP_TOLERANCE_CONCURRENT_MOTION
Definition: ObjectLearningByPushingDefinitions.h:238
CObjectHypothesis::vCylinderAxis
Vec3d vCylinderAxis
Definition: ObjectHypothesis.h:306
CMSERDescriptor::nSize
int nSize
Definition: ObjectHypothesis.h:80
CObjectHypothesis::vCenter
Vec3d vCenter
Definition: ObjectHypothesis.h:311
CObjectHypothesis::nHypothesisNumber
int nHypothesisNumber
Definition: ObjectHypothesis.h:290
OLP_MIN_SIZE_LCCP_SEGMENT
#define OLP_MIN_SIZE_LCCP_SEGMENT
Definition: ObjectLearningByPushingDefinitions.h:300
CHypothesisPoint::pFeatureDescriptors
CSIFTFeatureArray * pFeatureDescriptors
Definition: ObjectHypothesis.h:240
OLP_MAX_SIZE_LCCP_SEGMENT
#define OLP_MAX_SIZE_LCCP_SEGMENT
Definition: ObjectLearningByPushingDefinitions.h:301
EPS
#define EPS
Definition: gdiam.cpp:1945
COLPTools::CreateSegmentationProbabilityMap
void CreateSegmentationProbabilityMap(const CObjectHypothesis *pHypothesis, const CCalibration *calibration, CByteImage *&pProbabilityImage)
Definition: OLPTools.cpp:1402
CMSERDescriptor3D::pRegionLeft
CMSERDescriptor * pRegionLeft
Definition: ObjectHypothesis.h:153
COLPTools::ClusterXMeans
void ClusterXMeans(const std::vector< CHypothesisPoint * > &aPoints, const int nMinNumClusters, const int nMaxNumClusters, const float fBICFactor, std::vector< std::vector< CHypothesisPoint * >> &aaPointClusters)
Definition: OLPTools.cpp:78
CHypothesisGeneration::Determinant4x4
float Determinant4x4(const float *pMatrix)
Definition: HypothesisGeneration.cpp:3865
CObjectHypothesis::fStdDev2
float fStdDev2
Definition: ObjectHypothesis.h:314
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:213
CObjectHypothesis::eSingleColored
@ eSingleColored
Definition: ObjectHypothesis.h:286
CHypothesisPoint::fColorR
float fColorR
Definition: ObjectHypothesis.h:238
GfxTL::Vec2d
VectorXD< 2, double > Vec2d
Definition: VectorXD.h:736
CObjectHypothesis
Definition: ObjectHypothesis.h:244
CObjectHypothesis::fStdDev1
float fStdDev1
Definition: ObjectHypothesis.h:313
CObjectHypothesis::fMaxExtent
float fMaxExtent
Definition: ObjectHypothesis.h:319
CObjectHypothesis::eUnstructured
@ eUnstructured
Definition: ObjectHypothesis.h:285
OLP_CLUSTERING_FACTOR_FOREGROUND_HYPOTHESES
#define OLP_CLUSTERING_FACTOR_FOREGROUND_HYPOTHESES
Definition: ObjectLearningByPushingDefinitions.h:277
CObjectHypothesisArray
CDynamicArrayTemplate< CObjectHypothesis * > CObjectHypothesisArray
Definition: ObjectHypothesis.h:362
CObjectHypothesis::mLastRotation
Mat3d mLastRotation
Definition: ObjectHypothesis.h:321
float
#define float
Definition: 16_Level.h:22
CObjectHypothesis::aNewPoints
std::vector< CHypothesisPoint * > aNewPoints
Definition: ObjectHypothesis.h:294
CMSERDescriptor3D::GetCopy
CMSERDescriptor3D * GetCopy()
Definition: ObjectHypothesis.h:129
CHypothesisPoint::ePointType
EPointType ePointType
Definition: ObjectHypothesis.h:237
CObjectHypothesis::vSecondAxis
Vec3d vSecondAxis
Definition: ObjectHypothesis.h:308
OLP_EFFORT_MODIFICATOR
#define OLP_EFFORT_MODIFICATOR
Definition: ObjectLearningByPushingDefinitions.h:86
ARMARX_VERBOSE_S
#define ARMARX_VERBOSE_S
Definition: Logging.h:207
COLPTools::FilterForegroundPoints
void FilterForegroundPoints(const std::vector< CHypothesisPoint * > &aAllPoints, const CByteImage *pForegroundImage, const CCalibration *calibration, std::vector< CHypothesisPoint * > &aForegroundPoints)
Definition: OLPTools.cpp:333
ARMARX_INFO_S
#define ARMARX_INFO_S
Definition: Logging.h:202
CHypothesisGeneration::CHypothesisGeneration
CHypothesisGeneration(CCalibration *calibration)
Definition: HypothesisGeneration.cpp:48
OLP_SCREENSHOT_PATH
#define OLP_SCREENSHOT_PATH
Definition: ObjectLearningByPushingDefinitions.h:221
CObjectHypothesis::ePlane
@ ePlane
Definition: ObjectHypothesis.h:282
Logging.h
CHypothesisPoint::fColorB
float fColorB
Definition: ObjectHypothesis.h:238
CHypothesisPoint::fMembershipProbability
float fMembershipProbability
Definition: ObjectHypothesis.h:239
CObjectHypothesis::vNormal
Vec3d vNormal
Definition: ObjectHypothesis.h:302
CObjectHypothesis::eCylinder
@ eCylinder
Definition: ObjectHypothesis.h:283
SaliencyCalculation.h
CHypothesisGeneration::CreatePlaneHypothesisDescriptor
CObjectHypothesis * CreatePlaneHypothesisDescriptor(const CVec3dArray &avPlanePoints, std::vector< CMSERDescriptor3D * > &aMSERs, std::vector< Vec3d > &aSigmaPoints, const CByteImage *pLeftColorImage, const CByteImage *pLeftGreyImage)
Definition: HypothesisGeneration.cpp:2723