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