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