MRPT  1.9.9
CFaceDetection.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #include "detectors-precomp.h" // Precompiled headers
10 
16 #include <mrpt/math/CMatrixF.h>
17 #include <mrpt/math/geometry.h>
19 #include <mrpt/opengl/CArrow.h>
20 #include <mrpt/opengl/CAxis.h>
24 #include <mrpt/opengl/CSphere.h>
25 #include <mrpt/slam/CICP.h>
27 #include <fstream>
28 
29 using namespace std;
30 using namespace mrpt;
31 using namespace mrpt::detectors;
32 using namespace mrpt::math;
33 using namespace mrpt::img;
34 using namespace mrpt::gui;
35 using namespace mrpt::math;
36 using namespace mrpt::opengl;
37 using namespace mrpt::system;
38 using namespace mrpt::maps;
39 using namespace mrpt::obs;
40 
41 //------------------------------------------------------------------------
42 // CFaceDetection
43 //------------------------------------------------------------------------
44 CFaceDetection::CFaceDetection()
45 {
46  m_measure.numPossibleFacesDetected = 0;
47  m_measure.numRealFacesDetected = 0;
48 
49  m_measure.faceNum = 0;
50 
51  m_timeLog.enable();
52 }
53 
54 //------------------------------------------------------------------------
55 // ~CFaceDetection
56 //------------------------------------------------------------------------
57 CFaceDetection::~CFaceDetection()
58 {
59  // Stop filters threads
60 
61  m_end_threads = true;
62 
63  m_enter_checkIfFacePlaneCov.set_value();
64  m_enter_checkIfFaceRegions.set_value();
65  m_enter_checkIfDiagonalSurface.set_value();
66 
67  m_thread_checkIfFaceRegions.join();
68  m_thread_checkIfFacePlaneCov.join();
69  m_thread_checkIfDiagonalSurface.join();
70 }
71 
72 //------------------------------------------------------------------------
73 // init
74 //------------------------------------------------------------------------
75 void CFaceDetection::init(const mrpt::config::CConfigFileBase& cfg)
76 {
77  m_options.confidenceThreshold =
78  cfg.read_int("FaceDetection", "confidenceThreshold", 240);
79  m_options.multithread = cfg.read_bool("FaceDetection", "multithread", true);
80  m_options.useCovFilter =
81  cfg.read_bool("FaceDetection", "useCovFilter", true);
82  m_options.useRegionsFilter =
83  cfg.read_bool("FaceDetection", "useRegionsFilter", true);
84  m_options.useSizeDistanceRelationFilter =
85  cfg.read_bool("FaceDetection", "useSizeDistanceRelationFilter", true);
86  m_options.useDiagonalDistanceFilter =
87  cfg.read_bool("FaceDetection", "useDiagonalDistanceFilter", true);
88 
89  m_testsOptions.planeThreshold =
90  cfg.read_double("FaceDetection", "planeThreshold", 50);
91  m_testsOptions.planeTest_eigenVal_top =
92  cfg.read_double("FaceDetection", "planeTest_eigenVal_top", 0.011);
93  m_testsOptions.planeTest_eigenVal_bottom =
94  cfg.read_double("FaceDetection", "planeTest_eigenVal_bottom", 0.0002);
95  m_testsOptions.regionsTest_sumDistThreshold_top = cfg.read_double(
96  "FaceDetection", "regionsTest_sumDistThreshold_top", 0.5);
97  m_testsOptions.regionsTest_sumDistThreshold_bottom = cfg.read_double(
98  "FaceDetection", "regionsTest_sumDistThreshold_bottom", 0.04);
99 
100  m_measure.takeTime = cfg.read_bool("FaceDetection", "takeTime", false);
101  m_measure.takeMeasures =
102  cfg.read_bool("FaceDetection", "takeMeasures", false);
103  m_measure.saveMeasurementsToFile =
104  cfg.read_bool("FaceDetection", "saveMeasurementsToFile", false);
105 
106  // Run filters threads
107  if (m_options.multithread)
108  {
109  if (m_options.useRegionsFilter)
110  m_thread_checkIfFaceRegions =
111  std::thread(dummy_checkIfFaceRegions, this);
112  if (m_options.useCovFilter)
113  m_thread_checkIfFacePlaneCov =
114  std::thread(dummy_checkIfFacePlaneCov, this);
115  if (m_options.useSizeDistanceRelationFilter ||
116  m_options.useDiagonalDistanceFilter)
117  m_thread_checkIfDiagonalSurface =
118  std::thread(dummy_checkIfDiagonalSurface, this);
119 
120  m_checkIfFacePlaneCov_res = false;
121  m_checkIfFaceRegions_res = true;
122  m_checkIfDiagonalSurface_res = true;
123  }
124 
125  cascadeClassifier.init(cfg);
126 }
127 
128 //------------------------------------------------------------------------
129 // detectObjects
130 //------------------------------------------------------------------------
131 void CFaceDetection::detectObjects_Impl(
133 {
134  MRPT_START
135 
136  // Detect possible faces
137  vector_detectable_object localDetected;
138 
139  // To obtain experimental results
140  {
141  if (m_measure.takeTime) m_timeLog.enter("Detection time");
142  }
143 
144  cascadeClassifier.detectObjects(obs, localDetected);
145 
146  // To obtain experimental results
147  {
148  if (m_measure.takeTime) m_timeLog.leave("Detection time");
149 
150  // if ( m_measure.takeMeasures )
151  m_measure.numPossibleFacesDetected += localDetected.size();
152  }
153 
154  // Check if we are using a 3D Camera and 3D points are saved
155  if ((IS_CLASS(obs, CObservation3DRangeScan)) && (localDetected.size() > 0))
156  {
157  // To obtain experimental results
158  {
159  if (m_measure.takeTime) m_timeLog.enter("Check if real face time");
160  }
161 
162  auto& o = static_cast<CObservation3DRangeScan&>(
163  const_cast<CObservation&>(obs));
164 
165  if (o.hasPoints3D)
166  {
167  // Vector to save detected objects to delete if they aren't a face
168  vector<size_t> deleteDetected;
169 
170  // Check if all possible detected faces satisfy a serial of
171  // constrains
172  for (unsigned int i = 0; i < localDetected.size(); i++)
173  {
174  CDetectable2D::Ptr rec =
175  std::dynamic_pointer_cast<CDetectable2D>(localDetected[i]);
176 
177  // Calculate initial and final rows and columns
178  unsigned int r1 = rec->m_y;
179  unsigned int r2 = rec->m_y + rec->m_height;
180  unsigned int c1 = rec->m_x;
181  unsigned int c2 = rec->m_x + rec->m_width;
182 
183  o.getZoneAsObs(m_lastFaceDetected, r1, r2, c1, c2);
184 
185  if (m_options.multithread)
186  {
187  // To obtain experimental results
188  {
189  if (m_measure.takeTime)
190  m_timeLog.enter("Multithread filters application");
191  }
192 
193  // Semaphores signal
194  if (m_options.useCovFilter)
195  m_enter_checkIfFacePlaneCov.set_value();
196  if (m_options.useRegionsFilter)
197  m_enter_checkIfFaceRegions.set_value();
198  if (m_options.useSizeDistanceRelationFilter ||
199  m_options.useDiagonalDistanceFilter)
200  m_enter_checkIfDiagonalSurface.set_value();
201 
202  // Semaphores wait
203  if (m_options.useCovFilter)
204  m_leave_checkIfFacePlaneCov.get_future().wait();
205  if (m_options.useRegionsFilter)
206  m_leave_checkIfFaceRegions.get_future().wait();
207  if (m_options.useSizeDistanceRelationFilter ||
208  m_options.useDiagonalDistanceFilter)
209  m_leave_checkIfDiagonalSurface.get_future().wait();
210 
211  // Check resutls
212  if (!m_checkIfFacePlaneCov_res ||
213  !m_checkIfFaceRegions_res ||
214  !m_checkIfDiagonalSurface_res)
215  deleteDetected.push_back(i);
216 
217  // To obtain experimental results
218  {
219  if (m_measure.takeTime)
220  m_timeLog.leave("Multithread filters application");
221  }
222 
223  m_measure.faceNum++;
224  }
225  else
226  {
227  // To obtain experimental results
228  {
229  if (m_measure.takeTime)
230  m_timeLog.enter("Secuential filters application");
231  }
232 
233  /////////////////////////////////////////////////////
234  // CMatrixDynamic<bool> region;
235  // experimental_segmentFace( m_lastFaceDetected, region);
236  /////////////////////////////////////////////////////
237 
238  // m_lastFaceDetected.intensityImage.saveToFile(format("%i.jpg",m_measure.faceNum));
239 
240  bool remove = false;
241 
242  // First check if we can adjust a plane to detected region
243  // as face, if yes it isn't a face!
244  if (m_options.useCovFilter &&
245  !checkIfFacePlaneCov(&m_lastFaceDetected))
246  {
247  deleteDetected.push_back(i);
248  remove = true;
249  }
250  else if (
251  m_options.useRegionsFilter &&
252  !checkIfFaceRegions(&m_lastFaceDetected))
253  {
254  deleteDetected.push_back(i);
255  remove = true;
256  }
257  else if (
258  (m_options.useSizeDistanceRelationFilter ||
259  m_options.useDiagonalDistanceFilter) &&
260  !checkIfDiagonalSurface(&m_lastFaceDetected))
261  {
262  deleteDetected.push_back(i);
263  remove = true;
264  }
265 
266  if (remove)
267  {
268  /*ofstream f;
269  f.open("deleted.txt", ofstream::app);
270  f << "Deleted: " << m_measure.faceNum << endl;
271  f.close();*/
272  m_measure.deletedRegions.push_back(m_measure.faceNum);
273  }
274 
275  m_measure.faceNum++;
276 
277  // To obtain experimental results
278  {
279  if (m_measure.takeTime)
280  m_timeLog.leave("Secuential filters application");
281  }
282  }
283  }
284 
285  // Delete non faces
286  for (unsigned int i = deleteDetected.size(); i > 0; i--)
287  localDetected.erase(
288  localDetected.begin() + deleteDetected[i - 1]);
289  }
290 
291  // Convert 2d detected objects to 3d
292  for (const auto& i : localDetected)
293  {
295  new CDetectable3D(std::dynamic_pointer_cast<CDetectable2D>(i)));
296  detected.push_back(object3d);
297  }
298 
299  // To obtain experimental results
300  {
301  if (m_measure.takeTime) m_timeLog.leave("Check if real face time");
302  }
303  }
304  else // Not using a 3D camera
305  {
306  detected = localDetected;
307  }
308 
309  // To obtain experimental results
310  {
311  // if ( m_measure.takeMeasures )
312  m_measure.numRealFacesDetected += detected.size();
313  }
314 
315  MRPT_END
316 }
317 
318 //------------------------------------------------------------------------
319 // checkIfFacePlane
320 //------------------------------------------------------------------------
321 bool CFaceDetection::checkIfFacePlane(CObservation3DRangeScan* face)
322 {
323  vector<TPoint3D> points;
324 
325  size_t N = face->points3D_x.size();
326 
327  points.resize(N);
328 
329  for (size_t i = 0; i < N; i++)
330  points[i] = TPoint3D(
331  face->points3D_x.at(i), face->points3D_y.at(i),
332  face->points3D_z.at(i));
333 
334  // Try to ajust a plane
335  TPlane plane;
336 
337  // To obtain experimental results
338  {
339  if (m_measure.takeMeasures)
340  m_measure.errorEstimations.push_back(
341  (double)getRegressionPlane(points, plane));
342  }
343 
344  if (getRegressionPlane(points, plane) < m_testsOptions.planeThreshold)
345  return true;
346 
347  return false;
348 }
349 
350 void CFaceDetection::dummy_checkIfFacePlaneCov(CFaceDetection* obj)
351 {
352  obj->thread_checkIfFacePlaneCov();
353 }
354 
355 void CFaceDetection::thread_checkIfFacePlaneCov()
356 {
357  for (;;)
358  {
359  m_enter_checkIfFacePlaneCov.get_future().wait();
360 
361  if (m_end_threads) break;
362 
363  // Perform filter
364  m_checkIfFacePlaneCov_res = checkIfFacePlaneCov(&m_lastFaceDetected);
365 
366  m_leave_checkIfFacePlaneCov.set_value();
367  }
368 }
369 
370 //------------------------------------------------------------------------
371 // checkIfFacePlaneCov
372 //------------------------------------------------------------------------
373 bool CFaceDetection::checkIfFacePlaneCov(CObservation3DRangeScan* face)
374 {
376 
377  // To obtain experimental results
378  {
379  if (m_measure.takeTime)
380  m_timeLog.enter("Check if face plane: covariance");
381  }
382 
383  // Get face region size
384  const unsigned int faceWidth = face->intensityImage.getWidth();
385  const unsigned int faceHeight = face->intensityImage.getHeight();
386 
387  // We work with a confidence image?
388  const bool confidence = face->hasConfidenceImage;
389 
390  // To fill with valid points
391  vector<CVectorFixedDouble<3>> pointsVector;
392 
393  CMatrixDynamic<bool> region; // To save the segmented region
394  experimental_segmentFace(*face, region);
395 
396  for (unsigned int j = 0; j < faceHeight; j++)
397  {
398  for (unsigned int k = 0; k < faceWidth; k++)
399  {
401 
402  // Don't take in account dark pixels
403  if (region(j, k) &&
404  (((!confidence) ||
405  ((confidence) &&
406  (face->confidenceImage.at<uint8_t>(k, j) >
407  m_options.confidenceThreshold) &&
408  (face->intensityImage.at<uint8_t>(k, j) > 50)))))
409  {
410  int position = faceWidth * j + k;
411  aux[0] = face->points3D_x[position];
412  aux[1] = face->points3D_y[position];
413  aux[2] = face->points3D_z[position];
414  pointsVector.push_back(aux);
415  }
416  }
417  }
418 
419  // Check if points vector is empty to avoid a future crash
420  if (pointsVector.empty()) return false;
421 
422  // experimental_viewFacePointsScanned( *face );
423 
424  // To obtain the covariance vector and eigenvalues
426  CMatrixDouble eVects;
427  std::vector<double> eVals;
428 
429  cov = covVector<vector<CVectorFixedDouble<3>>, CMatrixDouble>(pointsVector);
430 
431  cov.eig(eVects, eVals);
432 
433  // To obtain experimental results
434  {
435  if (m_measure.takeMeasures) m_measure.lessEigenVals.push_back(eVals[0]);
436 
437  if (m_measure.takeTime)
438  m_timeLog.leave("Check if face plane: covariance");
439 
440  // Uncomment if you want to analyze the calculated eigenvalues
441  // ofstream f;
442  /*f.open("eigenvalues.txt", ofstream::app);
443  f << m_measure.faceNum << " " << eVals[0] << endl;
444  f.close();*/
445 
446  // f.open("eigenvalues2.txt", ofstream::app);
447  cout << eVals[0] << " " << eVals[1] << " " << eVals[2] << " > ";
448  cout << eVals[0] / eVals[2] << endl;
449  // f << eVals[0]/eVals[2] << endl;
450  // f.close();
451  }
452 
453  if (m_measure.faceNum >= 314)
454  experimental_viewFacePointsAndEigenVects(pointsVector, eVects, eVals);
455 
456  // Check if the less eigenvalue is out of the permited area
457  // if ( ( eVals[0] > m_options.planeEigenValThreshold_down )
458  // && ( eVals[0] < m_options.planeEigenValThreshold_up ) )
459  if (eVals[0] / eVals[2] > 0.06)
460  {
461  // Uncomment if you want to save the face regions discarted by this
462  // filter
463  /*ofstream f;
464  f.open("deletedCOV.txt", ofstream::app);
465  f << m_measure.faceNum << endl;
466  f.close();*/
467 
468  return true; // Filter not passed
469  }
470 
471  return false; // Filter passed
472 
474 }
475 
476 void CFaceDetection::dummy_checkIfFaceRegions(CFaceDetection* obj)
477 {
478  obj->thread_checkIfFaceRegions();
479 }
480 
481 void CFaceDetection::thread_checkIfFaceRegions()
482 {
483  for (;;)
484  {
485  m_enter_checkIfFaceRegions.get_future().wait();
486 
487  if (m_end_threads) break;
488 
489  // Perform filter
490  m_checkIfFaceRegions_res = checkIfFaceRegions(&m_lastFaceDetected);
491 
492  m_leave_checkIfFaceRegions.set_value();
493  }
494 }
495 
496 //------------------------------------------------------------------------
497 // checkIfFaceRegions
498 //------------------------------------------------------------------------
499 
500 bool CFaceDetection::checkIfFaceRegions(CObservation3DRangeScan* face)
501 {
502  MRPT_START
503 
504  // To obtain experimental results
505  {
506  if (m_measure.takeTime) m_timeLog.enter("Check if face plane: regions");
507  }
508 
509  // To obtain region size
510  const unsigned int faceWidth = face->intensityImage.getWidth();
511  const unsigned int faceHeight = face->intensityImage.getHeight();
512 
513  // Initial vertical size of a region
514  unsigned int sectionVSize = faceHeight / 3.0;
515 
516  // Steps of this filter
517  // 1. To segment the region detected as face using a regions growing
518  // algorithm
519  // 2. To obtain the first and last column to work (a profile face detected
520  // can have a lateral area without to use)
521  // 3. To calculate the histogram of the upper zone of the region for
522  // determine if we use it (if this zone present
523  // a lot of dark pixels the measurements can be wrong)
524  // 4. To obtain the coordinates of pixels that form each subregion
525  // 5. To calculate medians or means of each subregion
526  // 6. To check subregions constrains
527 
528  vector<TPoint3D> points;
529 
530  TPoint3D meanPos[3][3] = {
531  {TPoint3D(0, 0, 0), TPoint3D(0, 0, 0), TPoint3D(0, 0, 0)},
532  {TPoint3D(0, 0, 0), TPoint3D(0, 0, 0), TPoint3D(0, 0, 0)},
533  {TPoint3D(0, 0, 0), TPoint3D(0, 0, 0), TPoint3D(0, 0, 0)}};
534  int numPoints[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
535 
536  vector<TPoint3D> regions2[9];
537 
538  //
539  // 1. To segment the region detected as face using a regions growing
540  // algorithm
541  //
542 
543  CMatrixDynamic<bool> region; // To save the segmented region
544  experimental_segmentFace(*face, region);
545 
546  //
547  // 2. To obtain the first and last column to work (a profile face detected
548  // can have a lateral area without to use)
549  //
550 
551  size_t start = faceWidth, end = 0;
552 
553  for (size_t r = 0; r < region.rows(); r++)
554  for (size_t c = 1; c < region.cols(); c++)
555  {
556  if ((!(region(r, c - 1))) && (region(r, c)))
557  {
558  if (c < start) start = c;
559  }
560  else if ((region(r, c - 1)) && (!(region(r, c))))
561  if (c > end) end = c;
562 
563  if ((c > end) && (region(r, c))) end = c;
564  }
565 
566  if (end == 0) end = faceWidth - 1; // Check if the end has't changed
567  if (end < 3 * (faceWidth / 4))
568  end = 3 * (faceWidth / 4); // To avoid spoiler
569  if (start == faceWidth) start = 0; // Check if the start has't changed
570  if (start > faceWidth / 4) start = faceWidth / 4; // To avoid spoiler
571 
572  // cout << "Start: " << start << " End: " << end << endl;
573 
574  // To use the start and end calculated to obtain the final regions limits
575  unsigned int utilWidth = faceWidth - start - (faceWidth - end);
576  unsigned int c1 = ceil(utilWidth / 3.0 + start);
577  unsigned int c2 = ceil(2 * (utilWidth / 3.0) + start);
578 
579  //
580  // 3. To calculate the histogram of the upper zone of the region for
581  // determine if we use it
582  //
583 
585  hist.setSize(1, 256, true);
586  experimental_calcHist(
587  face->intensityImage, start, 0, end, ceil(faceHeight * 0.1), hist);
588 
589  size_t countHist = 0;
590  for (size_t i = 0; i < 60; i++)
591  {
592  countHist += hist(0, i);
593  }
594 
595  size_t upLimit = 0;
596  size_t downLimit = faceHeight - 1;
597 
598  if (countHist > 10)
599  {
600  upLimit = floor(faceHeight * 0.1);
601  downLimit = floor(faceHeight * 0.9);
602  }
603 
604  // Uncomment it if you want to analyze the number of pixels that have more
605  // dark that the 60 gray tone
606  // m_meanHist.push_back( countHist );
607 
608  //
609  // 4. To obtain the coordinates of pixels that form each region
610  //
611 
612  unsigned int cont = 0;
613 
614  for (unsigned int r = 0; r < faceHeight; r++)
615  {
616  for (unsigned int c = 0; c < faceWidth; c++, cont++)
617  {
618  if ((r >= upLimit) && (r <= downLimit) && (region(r, c)) &&
619  (face->confidenceImage.at<uint8_t>(c, r, 0) >
620  m_options.confidenceThreshold) &&
621  (face->intensityImage.at<uint8_t>(c, r)) > 50)
622  {
623  unsigned int row, col;
624  if (r < sectionVSize + upLimit * 0.3)
625  row = 0;
626  else if (r < sectionVSize * 2 - upLimit * 0.15)
627  row = 1;
628  else
629  row = 2;
630 
631  if (c < c1)
632  col = 0;
633  else if (c < c2)
634  col = 1;
635  else
636  col = 2;
637 
638  TPoint3D point(
639  face->points3D_x[cont], face->points3D_y[cont],
640  face->points3D_z[cont]);
641  meanPos[row][col] = meanPos[row][col] + point;
642 
643  ++numPoints[row][col];
644 
645  if (row == 0 && col == 0)
646  regions2[0].emplace_back(
647  face->points3D_x[cont], face->points3D_y[cont],
648  face->points3D_z[cont]);
649  else if (row == 0 && col == 1)
650  regions2[1].emplace_back(
651  face->points3D_x[cont], face->points3D_y[cont],
652  face->points3D_z[cont]);
653  else if (row == 0 && col == 2)
654  regions2[2].emplace_back(
655  face->points3D_x[cont], face->points3D_y[cont],
656  face->points3D_z[cont]);
657  else if (row == 1 && col == 0)
658  regions2[3].emplace_back(
659  face->points3D_x[cont], face->points3D_y[cont],
660  face->points3D_z[cont]);
661  else if (row == 1 && col == 1)
662  regions2[4].emplace_back(
663  face->points3D_x[cont], face->points3D_y[cont],
664  face->points3D_z[cont]);
665  else if (row == 1 && col == 2)
666  regions2[5].emplace_back(
667  face->points3D_x[cont], face->points3D_y[cont],
668  face->points3D_z[cont]);
669  else if (row == 2 && col == 0)
670  regions2[6].emplace_back(
671  face->points3D_x[cont], face->points3D_y[cont],
672  face->points3D_z[cont]);
673  else if (row == 2 && col == 1)
674  regions2[7].emplace_back(
675  face->points3D_x[cont], face->points3D_y[cont],
676  face->points3D_z[cont]);
677  else
678  regions2[8].emplace_back(
679  face->points3D_x[cont], face->points3D_y[cont],
680  face->points3D_z[cont]);
681  }
682  }
683  }
684 
685  //
686  // 5. To calculate medians or means of each subregion
687  //
688 
689  vector<double> oldPointsX1;
690 
691  size_t middle1 = 0;
692  size_t middle2 = 0;
693 
694  if (regions2[0].size() > 0)
695  {
696  for (auto& i : regions2[0]) oldPointsX1.push_back(i.x);
697 
698  middle1 = floor((double)oldPointsX1.size() / 2);
699  nth_element(
700  oldPointsX1.begin(), oldPointsX1.begin() + middle1,
701  oldPointsX1.end()); // Obtain center element
702  }
703 
704  vector<double> oldPointsX2;
705 
706  if (regions2[2].size() > 0)
707  {
708  for (auto& i : regions2[2]) oldPointsX2.push_back(i.x);
709 
710  middle2 = floor((double)oldPointsX2.size() / 2);
711  nth_element(
712  oldPointsX2.begin(), oldPointsX2.begin() + middle2,
713  oldPointsX2.end()); // Obtain center element
714  }
715 
716  for (size_t i = 0; i < 3; i++)
717  for (size_t j = 0; j < 3; j++)
718  if (!numPoints[i][j])
719  meanPos[i][j] = TPoint3D(0, 0, 0);
720  else
721  meanPos[i][j] = meanPos[i][j] / numPoints[i][j];
722 
723  if (regions2[0].size() > 0) meanPos[0][0].x = oldPointsX1.at(middle1);
724 
725  if (regions2[2].size() > 0) meanPos[0][2].x = oldPointsX2.at(middle2);
726 
727  //
728  // 6. To check subregions constrains
729  //
730  vector<double> dist(5);
731  size_t res = checkRelativePosition(
732  meanPos[1][0], meanPos[1][2], meanPos[1][1], dist[0]);
733  res += res && checkRelativePosition(
734  meanPos[2][0], meanPos[2][2], meanPos[2][1], dist[1]);
735  res += res && checkRelativePosition(
736  meanPos[0][0], meanPos[0][2], meanPos[0][1], dist[2]);
737  res += res && checkRelativePosition(
738  meanPos[0][0], meanPos[2][2], meanPos[1][1], dist[3]);
739  res += res && checkRelativePosition(
740  meanPos[2][0], meanPos[0][2], meanPos[1][1], dist[4]);
741 
742  ofstream f;
743  f.open("dist.txt", ofstream::app);
744  f << sum(dist) << endl;
745  f.close();
746 
747  bool real = false;
748  if (!res)
749  real = true;
750  else if ((res = 1) && (sum(dist) > 0.04))
751  real = true;
752 
753  f.open("tam.txt", ofstream::app);
754  f << meanPos[0][1].distanceTo(meanPos[2][1]) << endl;
755  f.close();
756 
757  // experimental_viewRegions( regions2, meanPos );
758 
759  // cout << endl << meanPos[0][0] << "\t" << meanPos[0][1] << "\t" <<
760  // meanPos[0][2];
761  // cout << endl << meanPos[1][0] << "\t" << meanPos[1][1] << "\t" <<
762  // meanPos[1][2];
763  // cout << endl << meanPos[2][0] << "\t" << meanPos[2][1] << "\t" <<
764  // meanPos[2][2] << endl;
765 
766  // To obtain experimental results
767  {
768  if (m_measure.takeTime) m_timeLog.leave("Check if face plane: regions");
769  }
770 
771  if (real)
772  return true; // Filter passed
773  else
774  {
775  // Uncomment if you want to known what regions was discarted by this
776  // filter
777  /*ofstream f;
778  f.open("deletedSTRUCTURES.txt", ofstream::app);
779  f << m_measure.faceNum << endl;
780  f.close();*/
781 
782  return false; // Filter not passed
783  }
784 
785  MRPT_END
786 }
787 
788 //------------------------------------------------------------------------
789 // checkRelativePosition
790 //------------------------------------------------------------------------
791 
792 size_t CFaceDetection::checkRelativePosition(
793  const TPoint3D& p1, const TPoint3D& p2, const TPoint3D& p, double& dist)
794 {
795  double x1 = -p1.y;
796  double y1 = p1.x;
797 
798  double x2 = -p2.y;
799  double y2 = p2.x;
800 
801  double x = -p.y;
802  double y = p.x;
803 
804  double yIdeal = y1 + (((x - x1) * (y2 - y1)) / (x2 - x1));
805 
806  //////////////////////////////////
807 
808  /*double xaux = x2;
809  double yaux = y1;
810 
811  cout << "Grados= " << RAD2DEG(acos(
812  (xaux-x1)/(sqrt(pow(x1-x2,2)+pow(y1-y2,2))) )) << endl;*/
813 
814  ///////////////////////////////////////
815 
816  dist = yIdeal - y;
817 
818  if (y < yIdeal)
819  return 0;
820  else
821  return 1;
822 }
823 
824 void CFaceDetection::dummy_checkIfDiagonalSurface(CFaceDetection* obj)
825 {
826  obj->thread_checkIfDiagonalSurface();
827 }
828 
829 void CFaceDetection::thread_checkIfDiagonalSurface()
830 {
831  for (;;)
832  {
833  m_enter_checkIfDiagonalSurface.get_future().wait();
834 
835  if (m_end_threads) break;
836 
837  // Perform filter
838  m_checkIfDiagonalSurface_res =
839  checkIfDiagonalSurface(&m_lastFaceDetected);
840 
841  m_leave_checkIfDiagonalSurface.set_value();
842  }
843 }
844 
845 //------------------------------------------------------------------------
846 // checkIfDiagonalSurface
847 //------------------------------------------------------------------------
848 
849 bool CFaceDetection::checkIfDiagonalSurface(CObservation3DRangeScan* face)
850 {
851  MRPT_START
852 
853  // To obtain experimental results
854  {
855  if (m_options.useDiagonalDistanceFilter && m_measure.takeTime)
856  m_timeLog.enter("Check if face plane: diagonal distances");
857 
858  if (m_options.useSizeDistanceRelationFilter && m_measure.takeTime)
859  m_timeLog.enter("Check if face plane: size-distance relation");
860  }
861 
862  const unsigned int faceWidth = face->intensityImage.getWidth();
863  const unsigned int faceHeight = face->intensityImage.getHeight();
864 
865  // const float max_desv = 0.2;
866 
867  unsigned int x1 = ceil(faceWidth * 0.25);
868  unsigned int x2 = floor(faceWidth * 0.75);
869  unsigned int y1 = ceil(faceHeight * 0.15);
870  unsigned int y2 = floor(faceHeight * 0.85);
871 
872  vector<TPoint3D> points;
873  unsigned int cont = (y1 == 0 ? 0 : faceHeight * (y1 - 1));
874  CMatrixBool valids;
875 
876  valids.setSize(faceHeight, faceWidth);
877 
878  int total = 0;
879  double sumDepth = 0;
880 
881  for (unsigned int i = y1; i <= y2; i++)
882  {
883  cont += x1;
884 
885  for (unsigned int j = x1; j <= x2; j++, cont++)
886  {
887  if (face->confidenceImage.at<uint8_t>(j, i, 0) >
888  m_options.confidenceThreshold)
889  {
890  sumDepth += face->points3D_x[cont];
891  total++;
892  points.emplace_back(
893  face->points3D_x[cont], face->points3D_y[cont],
894  face->points3D_z[cont]);
895  }
896  }
897  cont += faceWidth - x2 - 1;
898  }
899 
900  double meanDepth = sumDepth / total;
901 
902  /*if ( m_measure.faceNum == 434 )
903  experimental_viewFacePointsScanned( *face );*/
904 
905  // experimental_viewFacePointsScanned( points );
906 
907  bool res = true;
908 
909  if (m_options.useSizeDistanceRelationFilter)
910  {
911  double maxFaceDistance = 0.5 + 1000 / (pow(faceWidth, 1.9));
912 
913  // To obtain experimental results
914  {
915  if (m_measure.takeTime)
916  m_timeLog.leave("Check if face plane: size-distance relation");
917 
918  if (m_options.useDiagonalDistanceFilter && m_measure.takeTime)
919  m_timeLog.leave("Check if face plane: diagonal distances");
920  }
921 
922  /*if ( maxFaceDistance > meanDepth )
923  return true;
924 
925  if ( !m_options.useDiagonalDistanceFilter )
926  return false;*/
927 
928  if (maxFaceDistance < meanDepth)
929  {
930  // Uncomment if you want to analyze the regions discarted by this
931  // filter
932  /*ofstream f;
933  f.open("deletedSIZEDISTANCE.txt", ofstream::app);
934  f << m_measure.faceNum << endl;
935  f.close();*/
936 
937  // if ( !m_options.useDiagonalDistanceFilter )
938  return false;
939  // else
940  // res = false;
941  }
942 
943  if (!m_options.useDiagonalDistanceFilter) return true;
944  }
945 
946  ofstream f;
947  /*f.open("relaciones1.txt", ofstream::app);
948  f << faceWidth << endl;
949  f.close();*/
950 
951  f.open("relaciones2.txt", ofstream::app);
952  f << meanDepth << endl;
953  f.close();
954 
955  // cout << m_measure.faceNum ;
956 
957  // experimental_viewFacePointsScanned( points );
958 
959  points.clear();
960 
961  cont = (y1 == 1 ? 0 : faceHeight * (y1 - 1));
962 
963  for (unsigned int i = y1; i <= y2; i++)
964  {
965  cont += x1;
966 
967  for (unsigned int j = x1; j <= x2; j++, cont++)
968  {
969  if ((face->confidenceImage.at<uint8_t>(j, i, 0) >
970  m_options.confidenceThreshold))
971  //&& ( face->points3D_x[cont] > meanDepth - max_desv )
972  //&& ( face->points3D_x[cont] < meanDepth + max_desv ) )
973  {
974  valids(i, j) = true;
975  points.emplace_back(
976  face->points3D_x[cont], face->points3D_y[cont],
977  face->points3D_z[cont]);
978  }
979  else
980  valids(i, j) = false;
981  }
982  cont += faceWidth - x2 - 1;
983  }
984 
985  /*if ( m_measure.faceNum > 838 )
986  experimental_viewFacePointsScanned( points );*/
987 
988  // if ( ( m_measure.faceNum == 225 ) || ( m_measure.faceNum == 226 ) )
989  // experimental_viewFacePointsScanned( points );
990 
991  double sumDistances = 0;
992  double distance;
993  int offsetIndex;
994 
995  cont = 0;
996 
997  for (unsigned int i = y1; i <= y2; i++)
998  {
999  cont += x1;
1000 
1001  for (unsigned int j = x1; j <= x2; j++, cont++)
1002  {
1003  if (valids(i, j))
1004  {
1005  // experimental_calcDiagDist( face, i, j, faceWidth, faceHeight,
1006  // valids, distance );
1007 
1008  distance = 0;
1009  if ((i + 1 <= y2) && (j + 1 <= x2))
1010  {
1011  if (valids(i + 1, j + 1))
1012  {
1013  TPoint3D p1(
1014  face->points3D_x[cont], face->points3D_y[cont],
1015  face->points3D_z[cont]);
1016  offsetIndex = cont + faceWidth + 1;
1018  face->points3D_x[offsetIndex],
1019  face->points3D_y[offsetIndex],
1020  face->points3D_z[offsetIndex]));
1021  }
1022  else
1023  {
1024  bool validOffset = true;
1025  int offset = 2;
1026 
1027  while (validOffset)
1028  {
1029  if ((i + offset <= y2) && (j + offset <= x2))
1030  {
1031  if (valids(i + offset, j + offset))
1032  {
1033  TPoint3D p1(
1034  face->points3D_x[cont],
1035  face->points3D_y[cont],
1036  face->points3D_z[cont]);
1037  offsetIndex = cont + faceWidth + offset;
1039  face->points3D_x[offsetIndex],
1040  face->points3D_y[offsetIndex],
1041  face->points3D_z[offsetIndex]));
1042  break;
1043  }
1044  offset++;
1045  }
1046  else
1047  validOffset = false;
1048  }
1049  }
1050  }
1051 
1052  sumDistances += distance;
1053  }
1054  }
1055  cont += faceWidth - x2 - 1;
1056  }
1057 
1058  // For experimental results
1059  {
1060  if (m_measure.takeMeasures)
1061  m_measure.sumDistances.push_back(sumDistances);
1062 
1063  ofstream fo;
1064  fo.open("distances.txt", ofstream::app);
1065  // f << m_measure.faceNum << " " << sumDistances << endl;
1066  fo << sumDistances << endl;
1067  fo.close();
1068 
1069  fo.open("distances2.txt", ofstream::app);
1070  fo << m_measure.faceNum << " " << sumDistances << endl;
1071  fo.close();
1072  }
1073 
1074  // double yMax = 3 + 3.8 / ( pow( meanDepth, 2 ) );
1075  // double yMax = 3 + 7 /( pow( meanDepth, 2) ) ;
1076  double yMax = 3 + 6 / (pow(meanDepth, 2));
1077  double yMin = 1 + 3.8 / (pow(meanDepth + 1.2, 2));
1078 
1079  // To obtain experimental results
1080  {
1081  if (m_measure.takeTime)
1082  m_timeLog.leave("Check if face plane: diagonal distances");
1083  }
1084 
1085  if (((sumDistances <= yMax) && (sumDistances >= yMin)) && (res))
1086  {
1087  /* Uncomment if you want to analyze the real size of each studied region
1088  / *ofstream f;
1089  f.open("sizes.txt", ofstream::app);
1090  double h = meanDepth/cos(DEG2RAD(faceHeight*0.2361111111111111));
1091  double realHigh = sin(DEG2RAD(faceHeight*0.2361111111111111))*h;
1092  f << realHigh << endl;
1093  f.close();*/
1094 
1095  return true;
1096  }
1097 
1098  // Uncomment if you want to analyze regions discarted by this filter
1099  /*if (( sumDistances > yMax ) || ( sumDistances < yMin ))
1100  {
1101  ofstream f;
1102  f.open("deletedDIAGONAL.txt", ofstream::app);
1103  f << m_measure.faceNum << endl;
1104  f.close();
1105  }*/
1106 
1107  return false;
1108 
1109  MRPT_END
1110 }
1111 
1112 //------------------------------------------------------------------------
1113 // checkIfDiagonalSurface2
1114 //------------------------------------------------------------------------
1115 
1116 bool CFaceDetection::checkIfDiagonalSurface2(CObservation3DRangeScan* face)
1117 {
1118  MRPT_START
1119 
1120  // To obtain experimental results
1121  {
1122  if (m_options.useDiagonalDistanceFilter && m_measure.takeTime)
1123  m_timeLog.enter("Check if face plane: diagonal distances");
1124 
1125  if (m_options.useSizeDistanceRelationFilter && m_measure.takeTime)
1126  m_timeLog.enter("Check if face plane: size-distance relation");
1127  }
1128 
1129  const unsigned int faceWidth = face->intensityImage.getWidth();
1130  const unsigned int faceHeight = face->intensityImage.getHeight();
1131 
1132  CMatrixDynamic<bool> region; // To save the segmented region
1133  experimental_segmentFace(*face, region);
1134 
1135  size_t cont = 0;
1136  size_t total = 0;
1137  float sumDepth = 0;
1138 
1139  vector<TPoint3D> points;
1140 
1141  for (unsigned int row = 0; row < faceHeight; row++)
1142  {
1143  for (unsigned int col = 0; col < faceWidth; col++, cont++)
1144  {
1145  if ((region(row, col)) &&
1146  (face->confidenceImage.at<uint8_t>(col, row) >
1147  m_options.confidenceThreshold))
1148  {
1149  sumDepth += face->points3D_x[cont];
1150  total++;
1151  points.emplace_back(
1152  face->points3D_x[cont], face->points3D_y[cont],
1153  face->points3D_z[cont]);
1154  }
1155  }
1156  }
1157 
1158  double meanDepth = sumDepth / total;
1159 
1160  bool res = true;
1161 
1162  if (m_options.useSizeDistanceRelationFilter)
1163  {
1164  double maxFaceDistance = 0.5 + 1000 / (pow(faceWidth, 1.9));
1165 
1166  // To obtain experimental results
1167  {
1168  if (m_measure.takeTime)
1169  m_timeLog.leave("Check if face plane: size-distance relation");
1170 
1171  if (m_options.useDiagonalDistanceFilter && m_measure.takeTime)
1172  m_timeLog.leave("Check if face plane: diagonal distances");
1173  }
1174 
1175  /*if ( maxFaceDistance > meanDepth )
1176  return true;
1177 
1178  if ( !m_options.useDiagonalDistanceFilter )
1179  return false;*/
1180 
1181  if (maxFaceDistance < meanDepth)
1182  {
1183  // Uncomment if you want to analyze the regions discarted by this
1184  // filter
1185  /*ofstream f;
1186  f.open("deletedSIZEDISTANCE.txt", ofstream::app);
1187  f << m_measure.faceNum << endl;
1188  f.close();*/
1189 
1190  // if ( !m_options.useDiagonalDistanceFilter )
1191  return false;
1192  // else
1193  // res = false;
1194  }
1195 
1196  if (!m_options.useDiagonalDistanceFilter) return true;
1197  }
1198 
1199  ofstream f;
1200  /*f.open("relaciones1.txt", ofstream::app);
1201  f << faceWidth << endl;
1202  f.close();*/
1203 
1204  f.open("relaciones2.txt", ofstream::app);
1205  f << meanDepth << endl;
1206  f.close();
1207 
1208  // cout << m_measure.faceNum ;
1209 
1210  // experimental_viewFacePointsScanned( points );
1211 
1212  points.clear();
1213 
1214  /*if ( m_measure.faceNum > 838 )
1215  experimental_viewFacePointsScanned( points );*/
1216 
1217  // if ( ( m_measure.faceNum == 225 ) || ( m_measure.faceNum == 226 ) )
1218  // experimental_viewFacePointsScanned( points );
1219 
1220  double sumDistances = 0;
1221  double distance;
1222  size_t offsetIndex = 0;
1223 
1224  cont = 0;
1225 
1226  for (unsigned int i = 0; i < faceHeight; i++)
1227  {
1228  for (unsigned int j = 0; j < faceWidth; j++, cont++)
1229  {
1230  if (region(i, j))
1231  {
1232  distance = 0;
1233  if ((i + 1 < faceHeight) && (j + 1 < faceWidth))
1234  {
1235  if (region(i + 1, j + 1))
1236  {
1237  TPoint3D p1(
1238  face->points3D_x[cont], face->points3D_y[cont],
1239  face->points3D_z[cont]);
1240  offsetIndex = cont + faceWidth + 1;
1242  face->points3D_x[offsetIndex],
1243  face->points3D_y[offsetIndex],
1244  face->points3D_z[offsetIndex]));
1245  }
1246  else
1247  {
1248  bool validOffset = true;
1249  int offset = 2;
1250 
1251  while (validOffset)
1252  {
1253  if ((i + offset < faceHeight) &&
1254  (j + offset < faceWidth))
1255  {
1256  if (region(i + offset, j + offset))
1257  {
1258  TPoint3D p1(
1259  face->points3D_x[cont],
1260  face->points3D_y[cont],
1261  face->points3D_z[cont]);
1262  offsetIndex = cont + faceWidth + offset;
1264  face->points3D_x[offsetIndex],
1265  face->points3D_y[offsetIndex],
1266  face->points3D_z[offsetIndex]));
1267  break;
1268  }
1269  offset++;
1270  }
1271  else
1272  validOffset = false;
1273  }
1274  }
1275  }
1276 
1277  sumDistances += distance;
1278  }
1279  }
1280  }
1281 
1282  // For experimental results
1283  {
1284  if (m_measure.takeMeasures)
1285  m_measure.sumDistances.push_back(sumDistances);
1286 
1287  ofstream fo;
1288  fo.open("distances.txt", ofstream::app);
1289  // f << m_measure.faceNum << " " << sumDistances << endl;
1290  fo << sumDistances << endl;
1291  fo.close();
1292 
1293  /*f.open("distances2.txt", ofstream::app);
1294  f << m_measure.faceNum << " " << sumDistances << endl;
1295  f.close();*/
1296  }
1297 
1298  // double yMax = 3 + 3.8 / ( pow( meanDepth, 2 ) );
1299  // double yMax = 3 + 7 /( pow( meanDepth, 2) ) ;
1300  double yMax = 3 + 11.8 / (pow(meanDepth, 0.9));
1301  double yMin = 1 + 3.8 / (pow(meanDepth + 7, 6));
1302 
1303  // To obtain experimental results
1304  {
1305  if (m_measure.takeTime)
1306  m_timeLog.leave("Check if face plane: diagonal distances");
1307  }
1308 
1309  if (((sumDistances <= yMax) && (sumDistances >= yMin)) && (res))
1310  {
1311  /* Uncomment if you want to analyze the real size of each studied region
1312  / *ofstream f;
1313  f.open("sizes.txt", ofstream::app);
1314  double h = meanDepth/cos(DEG2RAD(faceHeight*0.2361111111111111));
1315  double realHigh = sin(DEG2RAD(faceHeight*0.2361111111111111))*h;
1316  f << realHigh << endl;
1317  f.close();*/
1318 
1319  return true;
1320  }
1321 
1322  // Uncomment if you want to analyze regions discarted by this filter
1323  /*if (( sumDistances > yMax ) || ( sumDistances < yMin ))
1324  {
1325  ofstream f;
1326  f.open("deletedDIAGONAL.txt", ofstream::app);
1327  f << m_measure.faceNum << endl;
1328  f.close();
1329  }*/
1330 
1331  return false;
1332 
1333  MRPT_END
1334 }
1335 
1336 //------------------------------------------------------------------------
1337 // experimental_viewFacePointsScanned
1338 //------------------------------------------------------------------------
1339 
1340 void CFaceDetection::experimental_viewFacePointsScanned(
1342 {
1343  vector<float> xs, ys, zs;
1344 
1345  unsigned int N = face.points3D_x.size();
1346 
1347  xs.resize(N);
1348  ys.resize(N);
1349  zs.resize(N);
1350 
1351  for (unsigned int i = 0; i < N; i++)
1352  {
1353  xs[i] = face.points3D_x[i];
1354  ys[i] = face.points3D_y[i];
1355  zs[i] = face.points3D_z[i];
1356  }
1357 
1358  experimental_viewFacePointsScanned(xs, ys, zs);
1359 }
1360 
1361 //------------------------------------------------------------------------
1362 // experimental_ViewFacePointsScanned
1363 //------------------------------------------------------------------------
1364 
1365 void CFaceDetection::experimental_viewFacePointsScanned(
1366  const vector<TPoint3D>& points)
1367 {
1368  vector<float> xs, ys, zs;
1369 
1370  unsigned int N = points.size();
1371 
1372  xs.resize(N);
1373  ys.resize(N);
1374  zs.resize(N);
1375 
1376  for (unsigned int i = 0; i < N; i++)
1377  {
1378  xs[i] = points[i].x;
1379  ys[i] = points[i].y;
1380  zs[i] = points[i].z;
1381  }
1382 
1383  experimental_viewFacePointsScanned(xs, ys, zs);
1384 }
1385 
1386 //------------------------------------------------------------------------
1387 // experimental_viewFacePointsScanned
1388 //------------------------------------------------------------------------
1389 
1390 void CFaceDetection::experimental_viewFacePointsScanned(
1391  const vector<float>& xs, const vector<float>& ys, const vector<float>& zs)
1392 {
1394 
1395  win3D.setWindowTitle("3D Face detected (Scanned points)");
1396 
1397  win3D.resize(400, 300);
1398 
1399  win3D.setCameraAzimuthDeg(140);
1400  win3D.setCameraElevationDeg(20);
1401  win3D.setCameraZoom(6.0);
1402  win3D.setCameraPointingToPoint(2.5, 0, 0);
1403 
1406  gl_points->setPointSize(4.5);
1407 
1409 
1410  scene->insert(gl_points);
1411  scene->insert(mrpt::opengl::CGridPlaneXY::Create());
1412 
1413  CColouredPointsMap pntsMap;
1414 
1415  pntsMap.setAllPoints(xs, ys, zs);
1416 
1417  gl_points->loadFromPointsMap(&pntsMap);
1418 
1419  // gl_points->setColor(0,0.7,0.7,1);
1420 
1421  /*static int i = 0;
1422 
1423  if ( i == 2 )
1424  {
1425  mapa.setAllPoints( xs, ys, zs );
1426  i++;
1427  }
1428  else if ( i > 2 )
1429  {
1430  float run_time;
1431  CICP icp;
1432  CICP::TReturnInfo icp_info;
1433 
1434  icp.options.thresholdDist = 0.40;
1435  icp.options.thresholdAng = 0.40;
1436 
1437  CPose3DPDF::Ptr pdf= icp.Align3D(
1438  &mapa, // Map to align
1439  &pntsMap, // Reference map
1440  CPose3D(), // Initial gross estimate
1441  &run_time,
1442  &icp_info);
1443 
1444  cout << "ICP run took " << run_time << " secs." << endl;
1445  cout << "Goodness: " << 100*icp_info.goodness << "%" << endl;
1446  }
1447 
1448  i++;*/
1449 
1450  win3D.unlockAccess3DScene();
1451  win3D.repaint();
1452 
1453  system::pause();
1454 }
1455 
1456 //------------------------------------------------------------------------
1457 // experimental_viewFacePointsAndEigenVects
1458 //------------------------------------------------------------------------
1459 
1460 void CFaceDetection::experimental_viewFacePointsAndEigenVects(
1461  const vector<CVectorFixedDouble<3>>& pointsVector,
1462  const CMatrixDouble& eigenVect, const std::vector<double>& eigenVal)
1463 {
1464  vector<float> xs, ys, zs;
1465 
1466  const size_t size = pointsVector.size();
1467 
1468  xs.resize(size);
1469  ys.resize(size);
1470  zs.resize(size);
1471 
1472  for (size_t i = 0; i < size; i++)
1473  {
1474  xs[i] = pointsVector[i][0];
1475  ys[i] = pointsVector[i][1];
1476  zs[i] = pointsVector[i][2];
1477  }
1478 
1479  TPoint3D center(sum(xs) / size, sum(ys) / size, sum(zs) / size);
1480 
1482 
1483  win3D.setWindowTitle("3D Face detected (Scanned points)");
1484 
1485  win3D.resize(400, 300);
1486 
1487  win3D.setCameraAzimuthDeg(140);
1488  win3D.setCameraElevationDeg(20);
1489  win3D.setCameraZoom(6.0);
1490  win3D.setCameraPointingToPoint(2.5, 0, 0);
1491 
1494  gl_points->setPointSize(4.5);
1495 
1497 
1498  CSphere::Ptr sphere = std::make_shared<CSphere>(0.005f);
1499  sphere->setLocation(center);
1500  sphere->setColor(TColorf(0, 1, 0));
1501  scene->insert(sphere);
1502 
1503  TPoint3D E1(eigenVect(0, 0), eigenVect(0, 1), eigenVect(0, 2));
1504  TPoint3D E2(eigenVect(1, 0), eigenVect(1, 1), eigenVect(1, 2));
1505  TPoint3D E3(eigenVect(2, 0), eigenVect(2, 1), eigenVect(2, 2));
1506 
1507  // vector<TSegment3D> sgms;
1508 
1509  TPoint3D p1(center + E1 * eigenVal[0] * 100);
1510  TPoint3D p2(center + E2 * eigenVal[1] * 100);
1511  TPoint3D p3(center + E3 * eigenVal[2] * 100);
1512 
1513  CArrow::Ptr arrow1 = std::make_shared<CArrow>(
1514  center.x, center.y, center.z, p1.x, p1.y, p1.z);
1515  CArrow::Ptr arrow2 = std::make_shared<CArrow>(
1516  center.x, center.y, center.z, p2.x, p2.y, p2.z);
1517  CArrow::Ptr arrow3 = std::make_shared<CArrow>(
1518  center.x, center.y, center.z, p3.x, p3.y, p3.z);
1519 
1520  arrow1->setColor(TColorf(0, 1, 0));
1521  arrow2->setColor(TColorf(1, 0, 0));
1522  arrow3->setColor(TColorf(0, 0, 1));
1523 
1524  scene->insert(arrow1);
1525  scene->insert(arrow2);
1526  scene->insert(arrow3);
1527 
1528  // sgms.push_back( TSegment3D(center,center + E1*eigenVal[0]*100) );
1529  // sgms.push_back( TSegment3D(center,center + E2*eigenVal[1]*100) );
1530  // sgms.push_back( TSegment3D(center,center + E3*eigenVal[2]*100) );
1531  // mrpt::opengl::CSetOfLines::Ptr lines =
1532  // mrpt::opengl::CSetOfLines::Create( sgms );
1533  // lines->setColor(0,0,1,1);
1534  // lines->setLineWidth( 10 );
1535 
1536  // scene->insert( lines );
1537 
1538  scene->insert(gl_points);
1539  scene->insert(mrpt::opengl::CGridPlaneXY::Create());
1540 
1541  CColouredPointsMap pntsMap;
1542 
1543  pntsMap.setAllPoints(xs, ys, zs);
1544 
1545  gl_points->loadFromPointsMap(&pntsMap);
1546 
1547  win3D.unlockAccess3DScene();
1548  win3D.repaint();
1549 
1550  system::pause();
1551 }
1552 
1553 //------------------------------------------------------------------------
1554 // experimental_viewRegions
1555 //------------------------------------------------------------------------
1556 
1557 void CFaceDetection::experimental_viewRegions(
1558  const vector<TPoint3D> regions[9], const TPoint3D meanPos[3][3])
1559 {
1561 
1562  win3D.setWindowTitle("3D Face detected (Scanned points)");
1563 
1564  win3D.resize(400, 300);
1565 
1566  win3D.setCameraAzimuthDeg(140);
1567  win3D.setCameraElevationDeg(20);
1568  win3D.setCameraZoom(6.0);
1569  win3D.setCameraPointingToPoint(2.5, 0, 0);
1570 
1573  gl_points->setPointSize(6);
1574 
1576 
1577  if (meanPos != nullptr)
1578  {
1579  for (size_t i = 0; i < 3; i++)
1580  for (size_t j = 0; j < 3; j++)
1581  {
1582  CSphere::Ptr sphere = std::make_shared<CSphere>(0.005f);
1583  sphere->setLocation(meanPos[i][j]);
1584  sphere->setColor(TColorf(0, 1, 0));
1585  scene->insert(sphere);
1586  }
1587  }
1588 
1589  vector<TSegment3D> sgms;
1590  sgms.emplace_back(meanPos[0][0], meanPos[0][1]);
1591  sgms.emplace_back(meanPos[0][1], meanPos[0][2]);
1592  sgms.emplace_back(meanPos[1][0], meanPos[1][1]);
1593  sgms.emplace_back(meanPos[1][1], meanPos[1][2]);
1594  sgms.emplace_back(meanPos[2][0], meanPos[2][1]);
1595  sgms.emplace_back(meanPos[2][1], meanPos[2][2]);
1596  sgms.emplace_back(meanPos[0][0], meanPos[1][1]);
1597  sgms.emplace_back(meanPos[1][1], meanPos[2][2]);
1598  sgms.emplace_back(meanPos[2][0], meanPos[1][1]);
1599  sgms.emplace_back(meanPos[1][1], meanPos[0][2]);
1602  lines->setColor(0, 0, 1, 1);
1603  lines->setLineWidth(10);
1604 
1605  scene->insert(lines);
1606 
1607  scene->insert(gl_points);
1608  scene->insert(mrpt::opengl::CGridPlaneXY::Create());
1609  scene->insert(
1610  mrpt::opengl::CAxis::Create(-5, -5, -5, 5, 5, 5, 2.5, 3, true));
1611 
1612  CColouredPointsMap pntsMap;
1613 
1614  vector<float> xs, ys, zs;
1615 
1616  for (size_t i = 0; i < 9; i++)
1617  for (const auto& j : regions[i])
1618  {
1619  xs.push_back(j.x);
1620  ys.push_back(j.y);
1621  zs.push_back(j.z);
1622  }
1623 
1624  pntsMap.setAllPoints(xs, ys, zs);
1625 
1626  int cont = 0;
1627  float colors[9][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1},
1628  {1, 1, 0}, {1, 0, 1}, {0, 1, 1},
1629  {0.5f, 0.25f, 0}, {0.5f, 0, 0.25f}, {0, 0.35f, 0.5f}};
1630  for (size_t i = 0; i < 9; i++)
1631  {
1632  float R = colors[i][0];
1633  float G = colors[i][1];
1634  float B = colors[i][2];
1635 
1636  for (unsigned int j = 0; j < regions[i].size(); j++, cont++)
1637  pntsMap.setPointColor(cont, R, G, B);
1638  }
1639 
1640  gl_points->loadFromPointsMap(&pntsMap);
1641  // gl_points->setColorA(0.5);
1642 
1643  win3D.unlockAccess3DScene();
1644  win3D.repaint();
1645 
1646  system::pause();
1647 }
1648 
1649 //------------------------------------------------------------------------
1650 // experimental_segmentFace
1651 //------------------------------------------------------------------------
1652 
1653 void CFaceDetection::experimental_segmentFace(
1655 {
1656  const unsigned int faceWidth = face.intensityImage.getWidth();
1657  const unsigned int faceHeight = face.intensityImage.getHeight();
1658 
1659  region.setSize(faceWidth, faceHeight, true);
1660 
1661  unsigned int x1 = ceil(faceWidth * 0.4);
1662  unsigned int x2 = floor(faceWidth * 0.6);
1663  unsigned int y1 = ceil(faceHeight * 0.4);
1664  unsigned int y2 = floor(faceHeight * 0.6);
1665 
1666  region.setSize(faceHeight, faceWidth);
1667  CMatrixDynamic<size_t> toExpand;
1668  toExpand.setSize(faceHeight, faceWidth, true);
1669 
1670  unsigned int cont = (y1 <= 1 ? 0 : faceHeight * (y1 - 1));
1671 
1672  // int total = 0; // JL: Unused var
1673  // int numPoints = 0; // JL: Unused var
1674 
1676  // Normalize the image
1677  CMatrixFloat range2D = m_lastFaceDetected.rangeImage;
1678  range2D *= 1.0f / 5;
1679  img.setFromMatrix(range2D);
1680 
1681  // INITIALIZATION
1682  for (unsigned int i = y1; i <= y2; i++)
1683  {
1684  cont += x1;
1685 
1686  for (unsigned int j = x1; j <= x2; j++, cont++)
1687  {
1688  if (face.confidenceImage.at<uint8_t>(j, i) >
1689  m_options.confidenceThreshold)
1690  {
1691  toExpand(i, j) = 1;
1692  }
1693  }
1694  cont += faceWidth - x2;
1695  }
1696 
1697  // REGIONS GROWING
1698 
1699  bool newExpanded = true;
1700 
1701  while (newExpanded)
1702  {
1703  newExpanded = false;
1704 
1705  for (size_t row = 0; row < faceHeight; row++)
1706  {
1707  for (size_t col = 0; col < faceWidth; col++)
1708  {
1709  if (toExpand(row, col) == 1)
1710  {
1711  region(row, col) = true;
1712 
1713  int value = img.at<uint8_t>(col, row);
1714 
1715  if ((row > 0) && (toExpand(row - 1, col) != 2))
1716  {
1717  int value2 = img.at<uint8_t>(col, row - 1);
1718  if (abs(value - value2) < 2)
1719  {
1720  toExpand(row - 1, col) = 1;
1721  newExpanded = true;
1722  }
1723  }
1724 
1725  if ((row < faceWidth - 1) && (toExpand(row + 1, col) != 2))
1726  {
1727  int value2 = img.at<uint8_t>(col, row + 1);
1728  if (abs(value - value2) < 2)
1729  {
1730  toExpand(row + 1, col) = 1;
1731  newExpanded = true;
1732  }
1733  }
1734 
1735  if ((col > 0) && (toExpand(row, col - 1) != 2))
1736  {
1737  int value2 = img.at<uint8_t>(col - 1, row);
1738  if (abs(value - value2) < 2)
1739  {
1740  toExpand(row, col - 1) = 1;
1741  newExpanded = true;
1742  }
1743  }
1744 
1745  if ((col < faceHeight - 1) && (toExpand(row, col + 1) != 2))
1746  {
1747  int value2 = img.at<uint8_t>(col + 1, row);
1748  if (abs(value - value2) < 2)
1749  {
1750  toExpand(row, col + 1) = 1;
1751  newExpanded = true;
1752  }
1753  }
1754 
1755  toExpand(row, col) = 2;
1756  }
1757  }
1758  }
1759  }
1760 
1761  for (unsigned int row = 0; row < faceHeight; row++)
1762  {
1763  for (unsigned int col = 0; col < faceWidth; col++)
1764  {
1765  if (!(region(row, col)))
1766  {
1767  img.setPixel(col, row, 0);
1768  }
1769  }
1770  }
1771 
1772  // Uncomment if you want to see the resultant region segmented
1773  if (m_measure.faceNum >= 314)
1774  {
1775  CDisplayWindow win("Live video");
1776 
1777  win.showImage(img);
1778  system::pause();
1779  }
1780 }
1781 
1782 //------------------------------------------------------------------------
1783 // experimental_calcHist
1784 //------------------------------------------------------------------------
1785 
1786 void CFaceDetection::experimental_calcHist(
1787  const CImage& face, const size_t& c1, const size_t& r1, const size_t& c2,
1788  const size_t& r2, CMatrixDynamic<unsigned int>& hist)
1789 {
1790  TImageSize size;
1791  face.getSize(size);
1792  for (size_t row = r1; row <= r2; row++)
1793  for (size_t col = c1; col <= c2; col++)
1794  {
1795  auto value = face.at<uint8_t>(col, row);
1796  int count = hist(0, value) + 1;
1797  hist(0, value) = count;
1798  }
1799 }
1800 
1801 //------------------------------------------------------------------------
1802 // experimental_showMeasurements
1803 //------------------------------------------------------------------------
1804 
1805 void CFaceDetection::experimental_showMeasurements()
1806 {
1807  // This method execution time is not critical because it's executed only at
1808  // the end
1809  // or a few times in user application
1810 
1811  ofstream f;
1812  f.open("statistics.txt", ofstream::app);
1813 
1814  if (m_measure.lessEigenVals.size() > 0)
1815  {
1816  double meanEigenVal, stdEigenVal;
1817  double minEigenVal = *min_element(
1818  m_measure.lessEigenVals.begin(), m_measure.lessEigenVals.end());
1819  double maxEigenVal = *max_element(
1820  m_measure.lessEigenVals.begin(), m_measure.lessEigenVals.end());
1821 
1822  meanAndStd(m_measure.lessEigenVals, meanEigenVal, stdEigenVal);
1823 
1824  cout << endl
1825  << "Statistical data about eigen values calculated of regions "
1826  "detected as faces"
1827  << endl;
1828  cout << "Min eigenVal: " << minEigenVal << endl;
1829  cout << "Max eigenVal: " << maxEigenVal << endl;
1830  cout << "Mean eigenVal: " << meanEigenVal << endl;
1831  cout << "Standard Desv: " << stdEigenVal << endl;
1832 
1833  if (m_measure.saveMeasurementsToFile)
1834  {
1835  f << endl
1836  << "Statistical data about eigen values calculated of regions "
1837  "detected as faces"
1838  << endl;
1839  f << "Min eigenVal: " << minEigenVal << endl;
1840  f << "Max eigenVal: " << maxEigenVal << endl;
1841  f << "Mean eigenVal: " << meanEigenVal << endl;
1842  f << "Standard Desv: " << stdEigenVal << endl;
1843  }
1844  }
1845 
1846  if (m_measure.sumDistances.size() > 0)
1847  {
1848  double meanSumDist, stdSumDist;
1849  double minSumDist = *min_element(
1850  m_measure.sumDistances.begin(), m_measure.sumDistances.end());
1851  double maxSumDist = *max_element(
1852  m_measure.sumDistances.begin(), m_measure.sumDistances.end());
1853 
1854  meanAndStd(m_measure.sumDistances, meanSumDist, stdSumDist);
1855 
1856  cout << endl << "Statistical data about sum of distances" << endl;
1857  cout << "Min sumDistances: " << minSumDist << endl;
1858  cout << "Max sumDistances: " << maxSumDist << endl;
1859  cout << "Mean sumDistances: " << meanSumDist << endl;
1860  cout << "Standard Desv: " << stdSumDist << endl;
1861 
1862  if (m_measure.saveMeasurementsToFile)
1863  {
1864  f << endl << "Statistical data about sum of distances" << endl;
1865  f << "Min sumDistances: " << minSumDist << endl;
1866  f << "Max sumDistances: " << maxSumDist << endl;
1867  f << "Mean sumDistances: " << meanSumDist << endl;
1868  f << "Standard Desv: " << stdSumDist << endl;
1869  }
1870  }
1871 
1872  if (m_measure.errorEstimations.size() > 0)
1873  {
1874  double meanEstimationErr, stdEstimationErr;
1875  double minEstimationErr = *min_element(
1876  m_measure.errorEstimations.begin(),
1877  m_measure.errorEstimations.end());
1878  double maxEstimationErr = *max_element(
1879  m_measure.errorEstimations.begin(),
1880  m_measure.errorEstimations.end());
1881 
1882  meanAndStd(
1883  m_measure.errorEstimations, meanEstimationErr, stdEstimationErr);
1884 
1885  cout << endl
1886  << "Statistical data about estimation error adjusting a plane of "
1887  "regions detected as faces"
1888  << endl;
1889  cout << "Min estimation: " << minEstimationErr << endl;
1890  cout << "Max estimation: " << maxEstimationErr << endl;
1891  cout << "Mean estimation: " << meanEstimationErr << endl;
1892  cout << "Standard Desv: " << stdEstimationErr << endl;
1893 
1894  if (m_measure.saveMeasurementsToFile)
1895  {
1896  f << endl
1897  << "Statistical data about estimation error adjusting a plane of "
1898  "regions detected as faces"
1899  << endl;
1900  f << "Min estimation: " << minEstimationErr << endl;
1901  f << "Max estimation: " << maxEstimationErr << endl;
1902  f << "Mean estimation: " << meanEstimationErr << endl;
1903  f << "Standard Desv: " << stdEstimationErr << endl;
1904  }
1905  }
1906 
1907  cout << endl << "Data about number of faces" << endl;
1908  cout << "Possible faces detected: " << m_measure.numPossibleFacesDetected
1909  << endl;
1910  cout << "Real faces detected: " << m_measure.numRealFacesDetected << endl;
1911 
1912  if (m_meanHist.size() > 0)
1913  {
1914  double minHist = *min_element(m_meanHist.begin(), m_meanHist.end());
1915  double maxHist = *max_element(m_meanHist.begin(), m_meanHist.end());
1916  double meanHist;
1917  double stdHist;
1918  meanAndStd(m_meanHist, meanHist, stdHist);
1919 
1920  cout << endl << "Mean hist: " << meanHist << endl;
1921  cout << "Min hist: " << minHist << endl;
1922  cout << "Max hist: " << maxHist << endl;
1923  cout << "Stdv: " << stdHist << endl;
1924  }
1925 
1926  if (m_measure.saveMeasurementsToFile)
1927  {
1928  f << endl << "Data about number of faces" << endl;
1929  f << "Possible faces detected: " << m_measure.numPossibleFacesDetected
1930  << endl;
1931  f << "Real faces detected: " << m_measure.numRealFacesDetected << endl;
1932  }
1933 
1934  if (m_measure.takeTime && m_measure.saveMeasurementsToFile)
1935  f << endl << m_timeLog.getStatsAsText();
1936 
1937  f.close();
1938 
1940 }
1941 
1942 //------------------------------------------------------------------------
1943 // debug_returnResults
1944 //------------------------------------------------------------------------
1945 
1946 void CFaceDetection::debug_returnResults(
1947  const std::vector<uint32_t>& falsePositives,
1948  const std::vector<uint32_t>& ignore, unsigned int& falsePositivesDeleted,
1949  unsigned int& realFacesDeleted)
1950 {
1951  const unsigned int numDeleted = m_measure.deletedRegions.size();
1952  const unsigned int numFalsePositives = falsePositives.size();
1953  const unsigned int numIgnored = ignore.size();
1954  unsigned int ignoredDetected = 0;
1955 
1956  falsePositivesDeleted = 0;
1957 
1958  for (unsigned int i = 0; i < numDeleted; i++)
1959  {
1960  unsigned int region = m_measure.deletedRegions[i];
1961 
1962  bool falsePositive = false;
1963 
1964  unsigned int j = 0;
1965  while (!falsePositive && (j < numFalsePositives))
1966  {
1967  if (region == falsePositives[j]) falsePositive = true;
1968  j++;
1969  }
1970 
1971  if (falsePositive)
1972  falsePositivesDeleted++;
1973  else
1974  {
1975  bool igno = false;
1976 
1977  j = 0;
1978  while (!igno && (j < numIgnored))
1979  {
1980  if (region == ignore[j]) igno = true;
1981  j++;
1982  }
1983 
1984  if (igno) ignoredDetected++;
1985  }
1986  }
1987 
1988  realFacesDeleted = numDeleted - falsePositivesDeleted - ignoredDetected;
1989 
1990  m_measure.faceNum = 0;
1991  m_measure.deletedRegions.clear();
1992 }
bool eig(Derived &eVecs, std::vector< Scalar > &eVals, bool sorted=true) const
Computes the eigenvectors and eigenvalues for a square, general matrix.
GLuint GLuint GLsizei count
Definition: glext.h:3532
void unlockAccess3DScene()
Unlocks the access to the internal 3D scene.
A compile-time fixed-size numeric matrix container.
Definition: CMatrixFixed.h:33
#define MRPT_START
Definition: exceptions.h:241
double x
X,Y,Z coordinates.
Definition: TPoint3D.h:83
static Ptr Create(Args &&... args)
#define MRPT_TRY_END
The end of a standard MRPT "try...catch()" block that allows tracing throw the call stack after an ex...
Definition: exceptions.h:213
void setWindowTitle(const std::string &str) override
Changes the window title.
mrpt::opengl::COpenGLScene::Ptr & get3DSceneAndLock()
Gets a reference to the smart shared pointer that holds the internal scene (carefuly read introductio...
void resize(unsigned int width, unsigned int height) override
Resizes the window, stretching the image to fit into the display area.
const double G
void setCameraPointingToPoint(float x, float y, float z)
Changes the camera parameters programmatically.
GLintptr offset
Definition: glext.h:3936
This file implements several operations that operate element-wise on individual or pairs of container...
Declares a class derived from "CObservation" that encapsules a 3D range scan measurement, as from a time-of-flight range camera or any other RGBD sensor.
STL namespace.
std::vector< CDetectableObject::Ptr > vector_detectable_object
GLsizei GLsizei GLuint * obj
Definition: glext.h:4085
static Ptr Create(Args &&... args)
Definition: CAxis.h:31
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
GLsizei const GLfloat * points
Definition: glext.h:5414
vector< std::vector< uint32_t > > falsePositives
#define MRPT_TRY_START
The start of a standard MRPT "try...catch()" block that allows tracing throw the call stack after an ...
Definition: exceptions.h:206
This class allows loading and storing values and vectors of different types from a configuration text...
This base provides a set of functions for maths stuff.
const GLubyte * c
Definition: glext.h:6406
double distanceTo(const TPoint3D &p) const
Point-to-point distance.
Definition: TPoint3D.h:162
void setAllPoints(const std::vector< float > &X, const std::vector< float > &Y, const std::vector< float > &Z)
Set all the points at once from vectors with X,Y and Z coordinates.
Definition: CPointsMap.h:693
GLint GLvoid * img
Definition: glext.h:3769
This class creates a window as a graphical user interface (GUI) for displaying images to the user...
CONTAINER::Scalar sum(const CONTAINER &v)
Computes the sum of all the elements.
GLuint GLuint end
Definition: glext.h:3532
A pair (x,y) of pixel coordinates (integer resolution).
Definition: TPixelCoord.h:39
This namespace contains representation of robot actions and observations.
3D Plane, represented by its equation
Definition: TPlane.h:22
#define IS_CLASS(obj, class_name)
True if the given reference to object (derived from mrpt::rtti::CObject) is of the given class...
Definition: CObject.h:146
double getRegressionPlane(const std::vector< TPoint3D > &points, TPlane &plane)
Using eigenvalues, gets the best fitting plane for a set of 3D points.
Definition: geometry.cpp:2150
double read_double(const std::string &section, const std::string &name, double defaultValue, bool failIfNotFound=false) const
Specific class for face detection.
A map of 2D/3D points with individual colours (RGB).
CMatrixDouble cov(const MATRIX &v)
Computes the covariance matrix from a list of samples in an NxM matrix, where each row is a sample...
Definition: ops_matrices.h:149
mrpt::gui::CDisplayWindow3D::Ptr win
size_type rows() const
Number of rows in the matrix.
size_type cols() const
Number of columns in the matrix.
void pause(const std::string &msg=std::string("Press any key to continue...")) noexcept
Shows the message "Press any key to continue" (or other custom message) to the current standard outpu...
Definition: os.cpp:432
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
GLdouble GLdouble GLdouble r
Definition: glext.h:3711
void meanAndStd(const VECTORLIKE &v, double &out_mean, double &out_std, bool unbiased=true)
Computes the standard deviation of a vector (or all elements of a matrix)
const float R
Declares a class that represents any robot&#39;s observation.
Definition: CObservation.h:43
bool read_bool(const std::string &section, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
GLenum GLenum GLvoid * row
Definition: glext.h:3580
void setSize(size_t row, size_t col, bool zeroNewElements=false)
Changes the size of matrix, maintaining the previous contents.
#define MRPT_END
Definition: exceptions.h:245
A RGB color - floats in the range [0,1].
Definition: TColor.h:78
void setCameraZoom(float zoom)
Changes the camera parameters programmatically.
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:15
GLenum GLint GLint y
Definition: glext.h:3542
Classes for creating GUI windows for 2D and 3D visualization.
Definition: about_box.h:14
GLsizei const GLfloat * value
Definition: glext.h:4134
GLsizeiptr size
Definition: glext.h:3934
GLuint res
Definition: glext.h:7385
GLenum GLint x
Definition: glext.h:3542
GLuint start
Definition: glext.h:3532
void repaint()
Repaints the window.
Lightweight 3D point.
Definition: TPoint3D.h:90
This template class provides the basic functionality for a general 2D any-size, resizable container o...
GLfloat GLfloat p
Definition: glext.h:6398
static Ptr Create(Args &&... args)
Definition: CGridPlaneXY.h:31
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
Definition: geometry.cpp:1891
static Ptr Create(Args &&... args)
Definition: CSetOfLines.h:33
void setCameraAzimuthDeg(float deg)
Changes the camera parameters programmatically.
GLenum GLuint GLint GLenum face
Definition: glext.h:8349
void setPointColor(size_t index, float R, float G, float B)
Changes just the color of a given point from the map.
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:147
void setCameraElevationDeg(float deg)
Changes the camera parameters programmatically.
A graphical user interface (GUI) for efficiently rendering 3D scenes in real-time.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: c1796881b Sat Nov 16 19:04:34 2019 +0100 at sáb nov 16 19:15:10 CET 2019