Visual Servoing Platform  version 3.1.0
vpMbtFaceDepthNormal.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Manage depth normal features for a particular face.
33  *
34  *****************************************************************************/
35 
36 #include <visp3/core/vpCPUFeatures.h>
37 #include <visp3/mbt/vpMbtFaceDepthNormal.h>
38 #include <visp3/mbt/vpMbtTukeyEstimator.h>
39 
40 #ifdef VISP_HAVE_PCL
41 #include <pcl/common/centroid.h>
42 #include <pcl/filters/extract_indices.h>
43 #include <pcl/segmentation/sac_segmentation.h>
44 #endif
45 
46 #if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2)
47 #include <emmintrin.h>
48 #define VISP_HAVE_SSE2 1
49 #endif
50 
51 #define USE_SSE_CODE 1
52 #if VISP_HAVE_SSE2 && USE_SSE_CODE
53 #define USE_SSE 1
54 #else
55 #define USE_SSE 0
56 #endif
57 
59  : m_cam(), m_clippingFlag(vpPolygon3D::NO_CLIPPING), m_distFarClip(100), m_distNearClip(0.001), m_hiddenFace(NULL),
60  m_planeObject(), m_polygon(NULL), m_useScanLine(false), m_faceActivated(false),
61  m_faceCentroidMethod(GEOMETRIC_CENTROID), m_faceDesiredCentroid(), m_faceDesiredNormal(),
62  m_featureEstimationMethod(ROBUST_FEATURE_ESTIMATION), m_isTracked(false), m_isVisible(false), m_listOfFaceLines(),
63  m_planeCamera(), m_pclPlaneEstimationMethod(2), // SAC_MSAC, see pcl/sample_consensus/method_types.h
64  m_pclPlaneEstimationRansacMaxIter(200), m_pclPlaneEstimationRansacThreshold(0.001), m_polygonLines()
65 {
66 }
67 
69 {
70  for (size_t i = 0; i < m_listOfFaceLines.size(); i++) {
71  delete m_listOfFaceLines[i];
72  }
73 }
74 
89  std::string name)
90 {
91  // Build a PolygonLine to be able to easily display the lines model
92  PolygonLine polygon_line;
93 
94  // Add polygon
95  polygon_line.m_poly.setNbPoint(2);
96  polygon_line.m_poly.addPoint(0, P1);
97  polygon_line.m_poly.addPoint(1, P2);
98 
99  polygon_line.m_poly.setClipping(m_clippingFlag);
100  polygon_line.m_poly.setNearClippingDistance(m_distNearClip);
101  polygon_line.m_poly.setFarClippingDistance(m_distFarClip);
102 
103  polygon_line.m_p1 = &polygon_line.m_poly.p[0];
104  polygon_line.m_p2 = &polygon_line.m_poly.p[1];
105 
106  m_polygonLines.push_back(polygon_line);
107 
108  // suppress line already in the model
109  bool already_here = false;
111 
112  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
113  ++it) {
114  l = *it;
115  if ((samePoint(*(l->p1), P1) && samePoint(*(l->p2), P2)) || (samePoint(*(l->p1), P2) && samePoint(*(l->p2), P1))) {
116  already_here = true;
117  l->addPolygon(polygon);
118  l->hiddenface = faces;
120  }
121  }
122 
123  if (!already_here) {
124  l = new vpMbtDistanceLine;
125 
127  l->buildFrom(P1, P2);
128  l->addPolygon(polygon);
129  l->hiddenface = faces;
131 
132  l->setIndex((unsigned int)m_listOfFaceLines.size());
133  l->setName(name);
134 
137 
138  if ((m_clippingFlag & vpPolygon3D::NEAR_CLIPPING) == vpPolygon3D::NEAR_CLIPPING)
140 
141  if ((m_clippingFlag & vpPolygon3D::FAR_CLIPPING) == vpPolygon3D::FAR_CLIPPING)
143 
144  m_listOfFaceLines.push_back(l);
145  }
146 }
147 
148 #ifdef VISP_HAVE_PCL
149 bool vpMbtFaceDepthNormal::computeDesiredFeatures(const vpHomogeneousMatrix &cMo, const unsigned int width,
150  const unsigned int height,
151  const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &point_cloud,
152  vpColVector &desired_features, const unsigned int stepX,
153  const unsigned int stepY
154 #if DEBUG_DISPLAY_DEPTH_NORMAL
155  ,
156  vpImage<unsigned char> &debugImage,
157  std::vector<std::vector<vpImagePoint> > &roiPts_vec
158 #endif
159 )
160 {
161  m_faceActivated = false;
162 
163  if (width == 0 || height == 0)
164  return false;
165 
166  std::vector<vpImagePoint> roiPts;
167  vpColVector desired_normal(3);
168 
169  computeROI(cMo, width, height, roiPts
170 #if DEBUG_DISPLAY_DEPTH_NORMAL
171  ,
172  roiPts_vec
173 #endif
174  );
175 
176  if (roiPts.size() <= 2) {
177 #ifndef NDEBUG
178  std::cerr << "Error: roiPts.size() <= 2 in computeDesiredFeatures" << std::endl;
179 #endif
180  return false;
181  }
182 
183  vpPolygon polygon_2d(roiPts);
184  vpRect bb = polygon_2d.getBoundingBox();
185 
186  unsigned int top = (unsigned int)std::max(0.0, bb.getTop());
187  unsigned int bottom = (unsigned int)std::min((double)height, std::max(0.0, bb.getBottom()));
188  unsigned int left = (unsigned int)std::max(0.0, bb.getLeft());
189  unsigned int right = (unsigned int)std::min((double)width, std::max(0.0, bb.getRight()));
190 
191  bb.setTop(top);
192  bb.setBottom(bottom);
193  bb.setLeft(left);
194  bb.setRight(right);
195 
196  // Keep only 3D points inside the projected polygon face
197  pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_face(new pcl::PointCloud<pcl::PointXYZ>);
198  std::vector<double> point_cloud_face_vec, point_cloud_face_custom;
199 
201  point_cloud_face_custom.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
202  point_cloud_face_vec.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
204  point_cloud_face_vec.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
206  point_cloud_face->reserve((size_t)(bb.getWidth() * bb.getHeight()));
207  }
208 
209  bool checkSSE2 = vpCPUFeatures::checkSSE2();
210 #if !USE_SSE
211  checkSSE2 = false;
212 #else
213  bool push = false;
214  double prev_x, prev_y, prev_z;
215 #endif
216 
217  double x = 0.0, y = 0.0;
218  for (unsigned int i = top; i < bottom; i += stepY) {
219  for (unsigned int j = left; j < right; j += stepX) {
220  if (pcl::isFinite((*point_cloud)(j, i)) && (*point_cloud)(j, i).z > 0 &&
221  (m_useScanLine ? (i < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getHeight() &&
222  j < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getWidth() &&
223  m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs()[i][j] == m_polygon->getIndex())
224  : polygon_2d.isInside(vpImagePoint(i, j)))) {
225 
227  point_cloud_face->push_back((*point_cloud)(j, i));
230  point_cloud_face_vec.push_back((*point_cloud)(j, i).x);
231  point_cloud_face_vec.push_back((*point_cloud)(j, i).y);
232  point_cloud_face_vec.push_back((*point_cloud)(j, i).z);
233 
235  // Add point for custom method for plane equation estimation
237 
238  if (checkSSE2) {
239 #if USE_SSE
240  if (!push) {
241  push = true;
242  prev_x = x;
243  prev_y = y;
244  prev_z = (*point_cloud)(j, i).z;
245  } else {
246  push = false;
247  point_cloud_face_custom.push_back(prev_x);
248  point_cloud_face_custom.push_back(x);
249 
250  point_cloud_face_custom.push_back(prev_y);
251  point_cloud_face_custom.push_back(y);
252 
253  point_cloud_face_custom.push_back(prev_z);
254  point_cloud_face_custom.push_back((*point_cloud)(j, i).z);
255  }
256 #endif
257  } else {
258  point_cloud_face_custom.push_back(x);
259  point_cloud_face_custom.push_back(y);
260  point_cloud_face_custom.push_back((*point_cloud)(j, i).z);
261  }
262  }
263  }
264 
265 #if DEBUG_DISPLAY_DEPTH_NORMAL
266  debugImage[i][j] = 255;
267 #endif
268  }
269  }
270  }
271 
272 #if USE_SSE
273  if (checkSSE2 && push) {
274  point_cloud_face_custom.push_back(prev_x);
275  point_cloud_face_custom.push_back(prev_y);
276  point_cloud_face_custom.push_back(prev_z);
277  }
278 #endif
279 
280  if (point_cloud_face->empty() && point_cloud_face_custom.empty() && point_cloud_face_vec.empty()) {
281  return false;
282  }
283 
284  // Face centroid computed by the different methods
285  vpColVector centroid_point(3);
286 
288  if (!computeDesiredFeaturesPCL(point_cloud_face, desired_features, desired_normal, centroid_point)) {
289  return false;
290  }
292  computeDesiredFeaturesSVD(point_cloud_face_vec, cMo, desired_features, desired_normal, centroid_point);
294  computeDesiredFeaturesRobustFeatures(point_cloud_face_custom, point_cloud_face_vec, cMo, desired_features,
295  desired_normal, centroid_point);
296  } else {
297  throw vpException(vpException::badValue, "Unknown feature estimation method!");
298  }
299 
300  computeDesiredNormalAndCentroid(cMo, desired_normal, centroid_point);
301 
302  m_faceActivated = true;
303 
304  return true;
305 }
306 #endif
307 
308 bool vpMbtFaceDepthNormal::computeDesiredFeatures(const vpHomogeneousMatrix &cMo, const unsigned int width,
309  const unsigned int height,
310  const std::vector<vpColVector> &point_cloud,
311  vpColVector &desired_features, const unsigned int stepX,
312  const unsigned int stepY
313 #if DEBUG_DISPLAY_DEPTH_NORMAL
314  ,
315  vpImage<unsigned char> &debugImage,
316  std::vector<std::vector<vpImagePoint> > &roiPts_vec
317 #endif
318 )
319 {
320  m_faceActivated = false;
321 
322  if (width == 0 || height == 0)
323  return false;
324 
325  std::vector<vpImagePoint> roiPts;
326  vpColVector desired_normal(3);
327 
328  computeROI(cMo, width, height, roiPts
329 #if DEBUG_DISPLAY_DEPTH_NORMAL
330  ,
331  roiPts_vec
332 #endif
333  );
334 
335  if (roiPts.size() <= 2) {
336 #ifndef NDEBUG
337  std::cerr << "Error: roiPts.size() <= 2 in computeDesiredFeatures" << std::endl;
338 #endif
339  return false;
340  }
341 
342  vpPolygon polygon_2d(roiPts);
343  vpRect bb = polygon_2d.getBoundingBox();
344 
345  unsigned int top = (unsigned int)std::max(0.0, bb.getTop());
346  unsigned int bottom = (unsigned int)std::min((double)height, std::max(0.0, bb.getBottom()));
347  unsigned int left = (unsigned int)std::max(0.0, bb.getLeft());
348  unsigned int right = (unsigned int)std::min((double)width, std::max(0.0, bb.getRight()));
349 
350  bb.setTop(top);
351  bb.setBottom(bottom);
352  bb.setLeft(left);
353  bb.setRight(right);
354 
355  // Keep only 3D points inside the projected polygon face
356  std::vector<double> point_cloud_face, point_cloud_face_custom;
357 
358  point_cloud_face.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
360  point_cloud_face_custom.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
361  }
362 
363  bool checkSSE2 = vpCPUFeatures::checkSSE2();
364 #if !USE_SSE
365  checkSSE2 = false;
366 #else
367  bool push = false;
368  double prev_x, prev_y, prev_z;
369 #endif
370 
371  double x = 0.0, y = 0.0;
372  for (unsigned int i = top; i < bottom; i += stepY) {
373  for (unsigned int j = left; j < right; j += stepX) {
374  if (point_cloud[i * width + j][2] > 0 &&
375  (m_useScanLine ? (i < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getHeight() &&
376  j < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getWidth() &&
377  m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs()[i][j] == m_polygon->getIndex())
378  : polygon_2d.isInside(vpImagePoint(i, j)))) {
379  // Add point
380  point_cloud_face.push_back(point_cloud[i * width + j][0]);
381  point_cloud_face.push_back(point_cloud[i * width + j][1]);
382  point_cloud_face.push_back(point_cloud[i * width + j][2]);
383 
385  // Add point for custom method for plane equation estimation
387 
388  if (checkSSE2) {
389 #if USE_SSE
390  if (!push) {
391  push = true;
392  prev_x = x;
393  prev_y = y;
394  prev_z = point_cloud[i * width + j][2];
395  } else {
396  push = false;
397  point_cloud_face_custom.push_back(prev_x);
398  point_cloud_face_custom.push_back(x);
399 
400  point_cloud_face_custom.push_back(prev_y);
401  point_cloud_face_custom.push_back(y);
402 
403  point_cloud_face_custom.push_back(prev_z);
404  point_cloud_face_custom.push_back(point_cloud[i * width + j][2]);
405  }
406 #endif
407  } else {
408  point_cloud_face_custom.push_back(x);
409  point_cloud_face_custom.push_back(y);
410  point_cloud_face_custom.push_back(point_cloud[i * width + j][2]);
411  }
412  }
413 
414 #if DEBUG_DISPLAY_DEPTH_NORMAL
415  debugImage[i][j] = 255;
416 #endif
417  }
418  }
419  }
420 
421 #if USE_SSE
422  if (checkSSE2 && push) {
423  point_cloud_face_custom.push_back(prev_x);
424  point_cloud_face_custom.push_back(prev_y);
425  point_cloud_face_custom.push_back(prev_z);
426  }
427 #endif
428 
429  if (point_cloud_face.empty() && point_cloud_face_custom.empty()) {
430  return false;
431  }
432 
433  // Face centroid computed by the different methods
434  vpColVector centroid_point(3);
435 
436 #ifdef VISP_HAVE_PCL
438  pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_face_pcl(new pcl::PointCloud<pcl::PointXYZ>);
439  point_cloud_face_pcl->reserve(point_cloud_face.size() / 3);
440 
441  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
442  point_cloud_face_pcl->push_back(
443  pcl::PointXYZ(point_cloud_face[3 * i], point_cloud_face[3 * i + 1], point_cloud_face[3 * i + 2]));
444  }
445 
446  computeDesiredFeaturesPCL(point_cloud_face_pcl, desired_features, desired_normal, centroid_point);
447  } else
448 #endif
450  computeDesiredFeaturesSVD(point_cloud_face, cMo, desired_features, desired_normal, centroid_point);
452  computeDesiredFeaturesRobustFeatures(point_cloud_face_custom, point_cloud_face, cMo, desired_features,
453  desired_normal, centroid_point);
454  } else {
455  throw vpException(vpException::badValue, "Unknown feature estimation method!");
456  }
457 
458  computeDesiredNormalAndCentroid(cMo, desired_normal, centroid_point);
459 
460  m_faceActivated = true;
461 
462  return true;
463 }
464 
465 #ifdef VISP_HAVE_PCL
466 bool vpMbtFaceDepthNormal::computeDesiredFeaturesPCL(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &point_cloud_face,
467  vpColVector &desired_features, vpColVector &desired_normal,
468  vpColVector &centroid_point)
469 {
470  try {
471  // Compute plane equation for this subset of point cloud
472  pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
473  pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
474  // Create the segmentation object
475  pcl::SACSegmentation<pcl::PointXYZ> seg;
476  // Optional
477  seg.setOptimizeCoefficients(true);
478  // Mandatory
479  seg.setModelType(pcl::SACMODEL_PLANE);
480  seg.setMethodType(m_pclPlaneEstimationMethod);
481  seg.setDistanceThreshold(m_pclPlaneEstimationRansacThreshold);
482  seg.setMaxIterations(m_pclPlaneEstimationRansacMaxIter);
483 
484  seg.setInputCloud(point_cloud_face);
485  seg.segment(*inliers, *coefficients);
486 
487  pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_face_extracted(new pcl::PointCloud<pcl::PointXYZ>);
488  // Create the filtering object
489  pcl::ExtractIndices<pcl::PointXYZ> extract;
490 
491  // Extract the inliers
492  extract.setInputCloud(point_cloud_face);
493  extract.setIndices(inliers);
494  extract.setNegative(false);
495  extract.filter(*point_cloud_face_extracted);
496 
497  pcl::PointXYZ centroid_point_pcl;
498  if (pcl::computeCentroid(*point_cloud_face_extracted, centroid_point_pcl)) {
499  pcl::PointXYZ face_normal;
500  computeNormalVisibility(coefficients->values[0], coefficients->values[1], coefficients->values[2],
501  centroid_point_pcl, face_normal);
502 
503  desired_features.resize(3, false);
504  desired_features[0] = -coefficients->values[0] / coefficients->values[3];
505  desired_features[1] = -coefficients->values[1] / coefficients->values[3];
506  desired_features[2] = -coefficients->values[2] / coefficients->values[3];
507 
508  desired_normal[0] = face_normal.x;
509  desired_normal[1] = face_normal.y;
510  desired_normal[2] = face_normal.z;
511 
512  centroid_point[0] = centroid_point_pcl.x;
513  centroid_point[1] = centroid_point_pcl.y;
514  centroid_point[2] = centroid_point_pcl.z;
515  } else {
516  std::cerr << "Cannot compute centroid!" << std::endl;
517  return false;
518  }
519  } catch (const pcl::PCLException &e) {
520  std::cerr << "Catch a PCL exception: " << e.what() << std::endl;
521  throw;
522  }
523 
524  return true;
525 }
526 #endif
527 
528 void vpMbtFaceDepthNormal::computeDesiredFeaturesRobustFeatures(const std::vector<double> &point_cloud_face_custom,
529  const std::vector<double> &point_cloud_face,
530  const vpHomogeneousMatrix &cMo,
531  vpColVector &desired_features,
532  vpColVector &desired_normal,
533  vpColVector &centroid_point)
534 {
535  std::vector<double> weights;
536  double den = 0.0;
537  estimateFeatures(point_cloud_face_custom, cMo, desired_features, weights);
538 
539  // Compute face centroid
540  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
541  centroid_point[0] += weights[i] * point_cloud_face[3 * i];
542  centroid_point[1] += weights[i] * point_cloud_face[3 * i + 1];
543  centroid_point[2] += weights[i] * point_cloud_face[3 * i + 2];
544 
545  den += weights[i];
546  }
547 
548  centroid_point[0] /= den;
549  centroid_point[1] /= den;
550  centroid_point[2] /= den;
551 
552  computeNormalVisibility(-desired_features[0], -desired_features[1], -desired_features[2], centroid_point,
553  desired_normal);
554 }
555 
556 void vpMbtFaceDepthNormal::computeDesiredFeaturesSVD(const std::vector<double> &point_cloud_face,
557  const vpHomogeneousMatrix &cMo, vpColVector &desired_features,
558  vpColVector &desired_normal, vpColVector &centroid_point)
559 {
560  vpColVector plane_equation_SVD;
561  estimatePlaneEquationSVD(point_cloud_face, cMo, plane_equation_SVD, centroid_point);
562 
563  desired_features.resize(3, false);
564  desired_features[0] = -plane_equation_SVD[0] / plane_equation_SVD[3];
565  desired_features[1] = -plane_equation_SVD[1] / plane_equation_SVD[3];
566  desired_features[2] = -plane_equation_SVD[2] / plane_equation_SVD[3];
567 
568  computeNormalVisibility(-desired_features[0], -desired_features[1], -desired_features[2], centroid_point,
569  desired_normal);
570 }
571 
573  const vpColVector &desired_normal,
574  const vpColVector &centroid_point)
575 {
576  // Compute desired centroid in the object frame
577  vpColVector centroid_cam(4);
578  centroid_cam[0] = centroid_point[0];
579  centroid_cam[1] = centroid_point[1];
580  centroid_cam[2] = centroid_point[2];
581  centroid_cam[3] = 1;
582 
583  vpColVector centroid_obj = cMo.inverse() * centroid_cam;
584  m_faceDesiredCentroid.setWorldCoordinates(centroid_obj[0], centroid_obj[1], centroid_obj[2]);
585 
586  // Compute desired face normal in the object frame
587  vpColVector face_normal_cam(4);
588  face_normal_cam[0] = desired_normal[0];
589  face_normal_cam[1] = desired_normal[1];
590  face_normal_cam[2] = desired_normal[2];
591  face_normal_cam[3] = 1;
592 
593  vpColVector face_normal_obj = cMo.inverse() * face_normal_cam;
594  m_faceDesiredNormal.setWorldCoordinates(face_normal_obj[0], face_normal_obj[1], face_normal_obj[2]);
595 }
596 
597 bool vpMbtFaceDepthNormal::computePolygonCentroid(const std::vector<vpPoint> &points_, vpPoint &centroid)
598 {
599  if (points_.empty()) {
600  return false;
601  }
602 
603  if (points_.size() < 2) {
604  centroid = points_[0];
605  return true;
606  }
607 
608  std::vector<vpPoint> points = points_;
609  points.push_back(points_.front());
610 
611  double A1 = 0.0, A2 = 0.0, c_x1 = 0.0, c_x2 = 0.0, c_y = 0.0, c_z = 0.0;
612 
613  for (size_t i = 0; i < points.size() - 1; i++) {
614  // projection onto xy plane
615  c_x1 += (points[i].get_X() + points[i + 1].get_X()) *
616  (points[i].get_X() * points[i + 1].get_Y() - points[i + 1].get_X() * points[i].get_Y());
617  c_y += (points[i].get_Y() + points[i + 1].get_Y()) *
618  (points[i].get_X() * points[i + 1].get_Y() - points[i + 1].get_X() * points[i].get_Y());
619  A1 += points[i].get_X() * points[i + 1].get_Y() - points[i + 1].get_X() * points[i].get_Y();
620 
621  // projection onto xz plane
622  c_x2 += (points[i].get_X() + points[i + 1].get_X()) *
623  (points[i].get_X() * points[i + 1].get_Z() - points[i + 1].get_X() * points[i].get_Z());
624  c_z += (points[i].get_Z() + points[i + 1].get_Z()) *
625  (points[i].get_X() * points[i + 1].get_Z() - points[i + 1].get_X() * points[i].get_Z());
626  A2 += points[i].get_X() * points[i + 1].get_Z() - points[i + 1].get_X() * points[i].get_Z();
627  }
628 
629  c_x1 /= 3.0 * A1;
630  c_y /= 3.0 * A1;
631  c_x2 /= 3.0 * A2;
632  c_z /= 3.0 * A2;
633 
634  if (A1 > A2) {
635  centroid.set_X(c_x1);
636  } else {
637  centroid.set_X(c_x2);
638  }
639 
640  centroid.set_Y(c_y);
641  centroid.set_Z(c_z);
642 
643  return true;
644 }
645 
646 void vpMbtFaceDepthNormal::computeROI(const vpHomogeneousMatrix &cMo, const unsigned int width,
647  const unsigned int height, std::vector<vpImagePoint> &roiPts
648 #if DEBUG_DISPLAY_DEPTH_NORMAL
649  ,
650  std::vector<std::vector<vpImagePoint> > &roiPts_vec
651 #endif
652 )
653 {
654  if (m_useScanLine || m_clippingFlag > 2)
655  m_cam.computeFov(width, height);
656 
657  if (m_useScanLine) {
658  for (std::vector<PolygonLine>::iterator it = m_polygonLines.begin(); it != m_polygonLines.end(); ++it) {
659  it->m_p1->changeFrame(cMo);
660  it->m_p2->changeFrame(cMo);
661 
662  vpImagePoint ip1, ip2;
663 
664  it->m_poly.changeFrame(cMo);
665  it->m_poly.computePolygonClipped(m_cam);
666 
667  if (it->m_poly.polyClipped.size() == 2 &&
668  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::NEAR_CLIPPING) == 0) &&
669  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::FAR_CLIPPING) == 0) &&
670  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::DOWN_CLIPPING) == 0) &&
671  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::UP_CLIPPING) == 0) &&
672  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::LEFT_CLIPPING) == 0) &&
673  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::RIGHT_CLIPPING) == 0)) {
674 
675  std::vector<std::pair<vpPoint, vpPoint> > linesLst;
676  m_hiddenFace->computeScanLineQuery(it->m_poly.polyClipped[0].first, it->m_poly.polyClipped[1].first, linesLst,
677  true);
678 
679  for (unsigned int i = 0; i < linesLst.size(); i++) {
680  linesLst[i].first.project();
681  linesLst[i].second.project();
682 
683  vpMeterPixelConversion::convertPoint(m_cam, linesLst[i].first.get_x(), linesLst[i].first.get_y(), ip1);
684  vpMeterPixelConversion::convertPoint(m_cam, linesLst[i].second.get_x(), linesLst[i].second.get_y(), ip2);
685 
686  it->m_imPt1 = ip1;
687  it->m_imPt2 = ip2;
688 
689  roiPts.push_back(ip1);
690  roiPts.push_back(ip2);
691 
692 #if DEBUG_DISPLAY_DEPTH_NORMAL
693  std::vector<vpImagePoint> roiPts_;
694  roiPts_.push_back(ip1);
695  roiPts_.push_back(ip2);
696  roiPts_vec.push_back(roiPts_);
697 #endif
698  }
699  }
700  }
701  } else {
702  // Get polygon clipped
703  m_polygon->getRoiClipped(m_cam, roiPts, cMo);
704 
705 #if DEBUG_DISPLAY_DEPTH_NORMAL
706  roiPts_vec.push_back(roiPts);
707 #endif
708  }
709 }
710 
712 
714 {
715  // Compute lines visibility, only for display
716  vpMbtDistanceLine *line;
717  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
718  ++it) {
719  line = *it;
720  bool isvisible = false;
721 
722  for (std::list<int>::const_iterator itindex = line->Lindex_polygon.begin(); itindex != line->Lindex_polygon.end();
723  ++itindex) {
724  int index = *itindex;
725  if (index == -1) {
726  isvisible = true;
727  } else {
728  if (line->hiddenface->isVisible((unsigned int)index)) {
729  isvisible = true;
730  }
731  }
732  }
733 
734  // Si la ligne n'appartient a aucune face elle est tout le temps visible
735  if (line->Lindex_polygon.empty())
736  isvisible = true; // Not sure that this can occur
737 
738  if (isvisible) {
739  line->setVisible(true);
740  } else {
741  line->setVisible(false);
742  }
743  }
744 }
745 
746 void vpMbtFaceDepthNormal::computeNormalVisibility(const double nx, const double ny, const double nz,
747  const vpHomogeneousMatrix &cMo, const vpCameraParameters &camera,
748  vpColVector &correct_normal, vpPoint &centroid)
749 {
750  vpColVector faceNormal(3);
751  faceNormal[0] = nx;
752  faceNormal[1] = ny;
753  faceNormal[2] = nz;
754  faceNormal.normalize();
755 
756  // Get polygon clipped
757  std::vector<vpImagePoint> roiPts;
758  m_polygon->getRoiClipped(camera, roiPts, cMo);
759 
760  std::vector<vpPoint> polyPts;
761  m_polygon->getPolygonClipped(polyPts);
762 
763  vpColVector e4(3);
765  computePolygonCentroid(polyPts, centroid);
766  centroid.project();
767 
768  e4[0] = -centroid.get_X();
769  e4[1] = -centroid.get_Y();
770  e4[2] = -centroid.get_Z();
771  e4.normalize();
772  } else {
773  double centroid_x = 0.0;
774  double centroid_y = 0.0;
775  double centroid_z = 0.0;
776 
777  for (size_t i = 0; i < polyPts.size(); i++) {
778  centroid_x += polyPts[i].get_X();
779  centroid_y += polyPts[i].get_Y();
780  centroid_z += polyPts[i].get_Z();
781  }
782 
783  centroid_x /= polyPts.size();
784  centroid_y /= polyPts.size();
785  centroid_z /= polyPts.size();
786 
787  e4[0] = -centroid_x;
788  e4[1] = -centroid_y;
789  e4[2] = -centroid_z;
790  e4.normalize();
791 
792  centroid.set_X(centroid_x);
793  centroid.set_Y(centroid_y);
794  centroid.set_Z(centroid_z);
795  }
796 
797  correct_normal.resize(3, false);
798  double angle = acos(vpColVector::dotProd(e4, faceNormal));
799  if (angle < M_PI_2) {
800  correct_normal = faceNormal;
801  } else {
802  correct_normal[0] = -faceNormal[0];
803  correct_normal[1] = -faceNormal[1];
804  correct_normal[2] = -faceNormal[2];
805  }
806 }
807 
808 #ifdef VISP_HAVE_PCL
809 void vpMbtFaceDepthNormal::computeNormalVisibility(const float nx, const float ny, const float nz,
810  const pcl::PointXYZ &centroid_point, pcl::PointXYZ &face_normal)
811 {
812  vpColVector faceNormal(3);
813  faceNormal[0] = nx;
814  faceNormal[1] = ny;
815  faceNormal[2] = nz;
816  faceNormal.normalize();
817 
818  vpColVector e4(3);
819  e4[0] = -centroid_point.x;
820  e4[1] = -centroid_point.y;
821  e4[2] = -centroid_point.z;
822  e4.normalize();
823 
824  double angle = acos(vpColVector::dotProd(e4, faceNormal));
825  if (angle < M_PI_2) {
826  face_normal = pcl::PointXYZ(faceNormal[0], faceNormal[1], faceNormal[2]);
827  } else {
828  face_normal = pcl::PointXYZ(-faceNormal[0], -faceNormal[1], -faceNormal[2]);
829  }
830 }
831 #endif
832 
833 void vpMbtFaceDepthNormal::computeNormalVisibility(const double nx, const double ny, const double nz,
834  const vpColVector &centroid_point, vpColVector &face_normal)
835 {
836  face_normal.resize(3, false);
837  face_normal[0] = nx;
838  face_normal[1] = ny;
839  face_normal[2] = nz;
840  face_normal.normalize();
841 
842  vpColVector e4 = -centroid_point;
843  e4.normalize();
844 
845  double angle = acos(vpColVector::dotProd(e4, face_normal));
846  if (angle >= M_PI_2) {
847  face_normal[0] = -face_normal[0];
848  face_normal[1] = -face_normal[1];
849  face_normal[2] = -face_normal[2];
850  }
851 }
852 
854 {
855  L.resize(3, 6, false, false);
856 
857  // Transform the plane equation for the current pose
860 
861  double ux = m_planeCamera.getA();
862  double uy = m_planeCamera.getB();
863  double uz = m_planeCamera.getC();
864  double D = m_planeCamera.getD();
865  double D2 = D * D;
866 
867  // Features
868  features.resize(3, false);
869  features[0] = -ux / D;
870  features[1] = -uy / D;
871  features[2] = -uz / D;
872 
873  // L_A
874  L[0][0] = ux * ux / D2;
875  L[0][1] = ux * uy / D2;
876  L[0][2] = ux * uz / D2;
877  L[0][3] = 0.0;
878  L[0][4] = uz / D;
879  L[0][5] = -uy / D;
880 
881  // L_B
882  L[1][0] = ux * uy / D2;
883  L[1][1] = uy * uy / D2;
884  L[1][2] = uy * uz / D2;
885  L[1][3] = -uz / D;
886  L[1][4] = 0.0;
887  L[1][5] = ux / D;
888 
889  // L_C
890  L[2][0] = ux * uz / D2;
891  L[2][1] = uy * uz / D2;
892  L[2][2] = uz * uz / D2;
893  L[2][3] = uy / D;
894  L[2][4] = -ux / D;
895  L[2][5] = 0.0;
896 }
897 
899  const vpCameraParameters &cam, const vpColor &col, const unsigned int thickness,
900  const bool displayFullModel)
901 {
902  if (m_polygon->isVisible() || displayFullModel) {
904 
905  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
906  ++it) {
907  vpMbtDistanceLine *line = *it;
908  line->display(I, cMo, cam, col, thickness, displayFullModel);
909  }
910  }
911 }
912 
914  const vpCameraParameters &cam, const vpColor &col, const unsigned int thickness,
915  const bool displayFullModel)
916 {
917  if (m_polygon->isVisible() || displayFullModel) {
919 
920  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
921  ++it) {
922  vpMbtDistanceLine *line = *it;
923  line->display(I, cMo, cam, col, thickness, displayFullModel);
924  }
925  }
926 }
927 
929  const vpCameraParameters &cam, const double scale,
930  const unsigned int thickness)
931 {
932  if (m_faceActivated /*&& m_isTracked*/ && m_isVisible) {
933  // Desired feature
934  vpPoint pt_centroid = m_faceDesiredCentroid;
935  pt_centroid.changeFrame(cMo);
936  pt_centroid.project();
937 
938  vpImagePoint im_centroid;
939  vpMeterPixelConversion::convertPoint(cam, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
940 
941  vpPoint pt_normal = m_faceDesiredNormal;
942  pt_normal.changeFrame(cMo);
943  pt_normal.project();
944 
945  vpPoint pt_extremity;
946  pt_extremity.set_X(pt_centroid.get_X() + pt_normal.get_X() * scale);
947  pt_extremity.set_Y(pt_centroid.get_Y() + pt_normal.get_Y() * scale);
948  pt_extremity.set_Z(pt_centroid.get_Z() + pt_normal.get_Z() * scale);
949  pt_extremity.project();
950 
951  vpImagePoint im_extremity;
952  vpMeterPixelConversion::convertPoint(cam, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
953 
954  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::blue, 4, 2, thickness);
955 
956  // Current feature
957  // Transform the plane equation for the current pose
960 
961  double ux = m_planeCamera.getA();
962  double uy = m_planeCamera.getB();
963  double uz = m_planeCamera.getC();
964 
965  vpColVector correct_normal;
966  vpCameraParameters cam_copy = cam;
967  cam_copy.computeFov(I.getWidth(), I.getHeight());
968  computeNormalVisibility(ux, uy, uz, cMo, cam_copy, correct_normal, pt_centroid);
969 
970  pt_centroid.project();
971  vpMeterPixelConversion::convertPoint(cam_copy, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
972 
973  pt_extremity.set_X(pt_centroid.get_X() + correct_normal[0] * scale);
974  pt_extremity.set_Y(pt_centroid.get_Y() + correct_normal[1] * scale);
975  pt_extremity.set_Z(pt_centroid.get_Z() + correct_normal[2] * scale);
976  pt_extremity.project();
977 
978  vpMeterPixelConversion::convertPoint(cam_copy, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
979 
980  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::red, 4, 2, thickness);
981  }
982 }
983 
985  const vpCameraParameters &cam, const double scale,
986  const unsigned int thickness)
987 {
988  if (m_faceActivated /*&& m_isTracked*/ && m_isVisible) {
989  // Desired feature
990  vpPoint pt_centroid = m_faceDesiredCentroid;
991  pt_centroid.changeFrame(cMo);
992  pt_centroid.project();
993 
994  vpImagePoint im_centroid;
995  vpMeterPixelConversion::convertPoint(cam, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
996 
997  vpPoint pt_normal = m_faceDesiredNormal;
998  pt_normal.changeFrame(cMo);
999  pt_normal.project();
1000 
1001  vpPoint pt_extremity;
1002  pt_extremity.set_X(pt_centroid.get_X() + pt_normal.get_X() * scale);
1003  pt_extremity.set_Y(pt_centroid.get_Y() + pt_normal.get_Y() * scale);
1004  pt_extremity.set_Z(pt_centroid.get_Z() + pt_normal.get_Z() * scale);
1005  pt_extremity.project();
1006 
1007  vpImagePoint im_extremity;
1008  vpMeterPixelConversion::convertPoint(cam, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1009 
1010  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::blue, 4, 2, thickness);
1011 
1012  // Current feature
1013  // Transform the plane equation for the current pose
1016 
1017  double ux = m_planeCamera.getA();
1018  double uy = m_planeCamera.getB();
1019  double uz = m_planeCamera.getC();
1020 
1021  vpColVector correct_normal;
1022  vpCameraParameters cam_copy = cam;
1023  cam_copy.computeFov(I.getWidth(), I.getHeight());
1024  computeNormalVisibility(ux, uy, uz, cMo, cam_copy, correct_normal, pt_centroid);
1025 
1026  pt_centroid.project();
1027  vpMeterPixelConversion::convertPoint(cam_copy, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
1028 
1029  pt_extremity.set_X(pt_centroid.get_X() + correct_normal[0] * scale);
1030  pt_extremity.set_Y(pt_centroid.get_Y() + correct_normal[1] * scale);
1031  pt_extremity.set_Z(pt_centroid.get_Z() + correct_normal[2] * scale);
1032  pt_extremity.project();
1033 
1034  vpMeterPixelConversion::convertPoint(cam_copy, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1035 
1036  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::red, 4, 2, thickness);
1037  }
1038 }
1039 
1040 void vpMbtFaceDepthNormal::estimateFeatures(const std::vector<double> &point_cloud_face, const vpHomogeneousMatrix &cMo,
1041  vpColVector &x_estimated, std::vector<double> &w)
1042 {
1043  vpMbtTukeyEstimator<double> tukey_robust;
1044  std::vector<double> residues(point_cloud_face.size() / 3);
1045 
1046  w.resize(point_cloud_face.size() / 3, 1.0);
1047 
1048  unsigned int max_iter = 30, iter = 0;
1049  double error = 0.0, prev_error = -1.0;
1050  double A = 0.0, B = 0.0, C = 0.0;
1051 
1052  Mat33<double> ATA_3x3;
1053 
1054  bool checkSSE2 = vpCPUFeatures::checkSSE2();
1055 #if !USE_SSE
1056  checkSSE2 = false;
1057 #endif
1058 
1059  if (checkSSE2) {
1060 #if USE_SSE
1061  while (std::fabs(error - prev_error) > 1e-6 && (iter < max_iter)) {
1062  if (iter == 0) {
1063  // Transform the plane equation for the current pose
1066 
1067  double ux = m_planeCamera.getA();
1068  double uy = m_planeCamera.getB();
1069  double uz = m_planeCamera.getC();
1070  double D = m_planeCamera.getD();
1071 
1072  // Features
1073  A = -ux / D;
1074  B = -uy / D;
1075  C = -uz / D;
1076 
1077  size_t cpt = 0;
1078  if (point_cloud_face.size() / 3 >= 2) {
1079  const double *ptr_point_cloud = &point_cloud_face[0];
1080  const __m128d vA = _mm_set1_pd(A);
1081  const __m128d vB = _mm_set1_pd(B);
1082  const __m128d vC = _mm_set1_pd(C);
1083  const __m128d vones = _mm_set1_pd(1.0);
1084 
1085  double *ptr_residues = &residues[0];
1086 
1087  for (; cpt <= point_cloud_face.size() - 6; cpt += 6, ptr_point_cloud += 6, ptr_residues += 2) {
1088  const __m128d vxi = _mm_loadu_pd(ptr_point_cloud);
1089  const __m128d vyi = _mm_loadu_pd(ptr_point_cloud + 2);
1090  const __m128d vZi = _mm_loadu_pd(ptr_point_cloud + 4);
1091  const __m128d vinvZi = _mm_div_pd(vones, vZi);
1092 
1093  const __m128d tmp =
1094  _mm_add_pd(_mm_add_pd(_mm_mul_pd(vA, vxi), _mm_mul_pd(vB, vyi)), _mm_sub_pd(vC, vinvZi));
1095  _mm_storeu_pd(ptr_residues, tmp);
1096  }
1097  }
1098 
1099  for (; cpt < point_cloud_face.size(); cpt += 3) {
1100  double xi = point_cloud_face[cpt];
1101  double yi = point_cloud_face[cpt + 1];
1102  double Zi = point_cloud_face[cpt + 2];
1103 
1104  residues[cpt / 3] = (A * xi + B * yi + C - 1 / Zi);
1105  }
1106  }
1107 
1108  tukey_robust.MEstimator(residues, w, 1e-2);
1109 
1110  __m128d vsum_wi2_xi2 = _mm_setzero_pd();
1111  __m128d vsum_wi2_yi2 = _mm_setzero_pd();
1112  __m128d vsum_wi2 = _mm_setzero_pd();
1113  __m128d vsum_wi2_xi_yi = _mm_setzero_pd();
1114  __m128d vsum_wi2_xi = _mm_setzero_pd();
1115  __m128d vsum_wi2_yi = _mm_setzero_pd();
1116 
1117  __m128d vsum_wi2_xi_Zi = _mm_setzero_pd();
1118  __m128d vsum_wi2_yi_Zi = _mm_setzero_pd();
1119  __m128d vsum_wi2_Zi = _mm_setzero_pd();
1120 
1121  // Estimate A, B, C
1122  size_t cpt = 0;
1123  if (point_cloud_face.size() / 3 >= 2) {
1124  const double *ptr_point_cloud = &point_cloud_face[0];
1125  double *ptr_w = &w[0];
1126 
1127  const __m128d vones = _mm_set1_pd(1.0);
1128 
1129  for (; cpt <= point_cloud_face.size() - 6; cpt += 6, ptr_point_cloud += 6, ptr_w += 2) {
1130  const __m128d vwi2 = _mm_mul_pd(_mm_loadu_pd(ptr_w), _mm_loadu_pd(ptr_w));
1131 
1132  const __m128d vxi = _mm_loadu_pd(ptr_point_cloud);
1133  const __m128d vyi = _mm_loadu_pd(ptr_point_cloud + 2);
1134  const __m128d vZi = _mm_loadu_pd(ptr_point_cloud + 4);
1135  const __m128d vinvZi = _mm_div_pd(vones, vZi);
1136 
1137  vsum_wi2_xi2 = _mm_add_pd(vsum_wi2_xi2, _mm_mul_pd(vwi2, _mm_mul_pd(vxi, vxi)));
1138  vsum_wi2_yi2 = _mm_add_pd(vsum_wi2_yi2, _mm_mul_pd(vwi2, _mm_mul_pd(vyi, vyi)));
1139  vsum_wi2 = _mm_add_pd(vsum_wi2, vwi2);
1140  vsum_wi2_xi_yi = _mm_add_pd(vsum_wi2_xi_yi, _mm_mul_pd(vwi2, _mm_mul_pd(vxi, vyi)));
1141  vsum_wi2_xi = _mm_add_pd(vsum_wi2_xi, _mm_mul_pd(vwi2, vxi));
1142  vsum_wi2_yi = _mm_add_pd(vsum_wi2_yi, _mm_mul_pd(vwi2, vyi));
1143 
1144  const __m128d vwi2_invZi = _mm_mul_pd(vwi2, vinvZi);
1145  vsum_wi2_xi_Zi = _mm_add_pd(vsum_wi2_xi_Zi, _mm_mul_pd(vxi, vwi2_invZi));
1146  vsum_wi2_yi_Zi = _mm_add_pd(vsum_wi2_yi_Zi, _mm_mul_pd(vyi, vwi2_invZi));
1147  vsum_wi2_Zi = _mm_add_pd(vsum_wi2_Zi, vwi2_invZi);
1148  }
1149  }
1150 
1151  double vtmp[2];
1152  _mm_storeu_pd(vtmp, vsum_wi2_xi2);
1153  double sum_wi2_xi2 = vtmp[0] + vtmp[1];
1154 
1155  _mm_storeu_pd(vtmp, vsum_wi2_yi2);
1156  double sum_wi2_yi2 = vtmp[0] + vtmp[1];
1157 
1158  _mm_storeu_pd(vtmp, vsum_wi2);
1159  double sum_wi2 = vtmp[0] + vtmp[1];
1160 
1161  _mm_storeu_pd(vtmp, vsum_wi2_xi_yi);
1162  double sum_wi2_xi_yi = vtmp[0] + vtmp[1];
1163 
1164  _mm_storeu_pd(vtmp, vsum_wi2_xi);
1165  double sum_wi2_xi = vtmp[0] + vtmp[1];
1166 
1167  _mm_storeu_pd(vtmp, vsum_wi2_yi);
1168  double sum_wi2_yi = vtmp[0] + vtmp[1];
1169 
1170  _mm_storeu_pd(vtmp, vsum_wi2_xi_Zi);
1171  double sum_wi2_xi_Zi = vtmp[0] + vtmp[1];
1172 
1173  _mm_storeu_pd(vtmp, vsum_wi2_yi_Zi);
1174  double sum_wi2_yi_Zi = vtmp[0] + vtmp[1];
1175 
1176  _mm_storeu_pd(vtmp, vsum_wi2_Zi);
1177  double sum_wi2_Zi = vtmp[0] + vtmp[1];
1178 
1179  for (; cpt < point_cloud_face.size(); cpt += 3) {
1180  double wi2 = w[cpt / 3] * w[cpt / 3];
1181 
1182  double xi = point_cloud_face[cpt];
1183  double yi = point_cloud_face[cpt + 1];
1184  double Zi = point_cloud_face[cpt + 2];
1185  double invZi = 1.0 / Zi;
1186 
1187  sum_wi2_xi2 += wi2 * xi * xi;
1188  sum_wi2_yi2 += wi2 * yi * yi;
1189  sum_wi2 += wi2;
1190  sum_wi2_xi_yi += wi2 * xi * yi;
1191  sum_wi2_xi += wi2 * xi;
1192  sum_wi2_yi += wi2 * yi;
1193 
1194  sum_wi2_xi_Zi += wi2 * xi * invZi;
1195  sum_wi2_yi_Zi += wi2 * yi * invZi;
1196  sum_wi2_Zi += wi2 * invZi;
1197  }
1198 
1199  ATA_3x3[0] = sum_wi2_xi2;
1200  ATA_3x3[1] = sum_wi2_xi_yi;
1201  ATA_3x3[2] = sum_wi2_xi;
1202  ATA_3x3[3] = sum_wi2_xi_yi;
1203  ATA_3x3[4] = sum_wi2_yi2;
1204  ATA_3x3[5] = sum_wi2_yi;
1205  ATA_3x3[6] = sum_wi2_xi;
1206  ATA_3x3[7] = sum_wi2_yi;
1207  ATA_3x3[8] = sum_wi2;
1208 
1209  Mat33<double> minv = ATA_3x3.inverse();
1210 
1211  A = minv[0] * sum_wi2_xi_Zi + minv[1] * sum_wi2_yi_Zi + minv[2] * sum_wi2_Zi;
1212  B = minv[3] * sum_wi2_xi_Zi + minv[4] * sum_wi2_yi_Zi + minv[5] * sum_wi2_Zi;
1213  C = minv[6] * sum_wi2_xi_Zi + minv[7] * sum_wi2_yi_Zi + minv[8] * sum_wi2_Zi;
1214 
1215  cpt = 0;
1216 
1217  // Compute error
1218  prev_error = error;
1219  error = 0.0;
1220 
1221  __m128d verror = _mm_set1_pd(0.0);
1222  if (point_cloud_face.size() / 3 >= 2) {
1223  const double *ptr_point_cloud = &point_cloud_face[0];
1224  const __m128d vA = _mm_set1_pd(A);
1225  const __m128d vB = _mm_set1_pd(B);
1226  const __m128d vC = _mm_set1_pd(C);
1227  const __m128d vones = _mm_set1_pd(1.0);
1228 
1229  double *ptr_residues = &residues[0];
1230 
1231  for (; cpt <= point_cloud_face.size() - 6; cpt += 6, ptr_point_cloud += 6, ptr_residues += 2) {
1232  const __m128d vxi = _mm_loadu_pd(ptr_point_cloud);
1233  const __m128d vyi = _mm_loadu_pd(ptr_point_cloud + 2);
1234  const __m128d vZi = _mm_loadu_pd(ptr_point_cloud + 4);
1235  const __m128d vinvZi = _mm_div_pd(vones, vZi);
1236 
1237  const __m128d tmp = _mm_add_pd(_mm_add_pd(_mm_mul_pd(vA, vxi), _mm_mul_pd(vB, vyi)), _mm_sub_pd(vC, vinvZi));
1238  verror = _mm_add_pd(verror, _mm_mul_pd(tmp, tmp));
1239 
1240  _mm_storeu_pd(ptr_residues, tmp);
1241  }
1242  }
1243 
1244  _mm_storeu_pd(vtmp, verror);
1245  error = vtmp[0] + vtmp[1];
1246 
1247  for (size_t idx = cpt; idx < point_cloud_face.size(); idx += 3) {
1248  double xi = point_cloud_face[idx];
1249  double yi = point_cloud_face[idx + 1];
1250  double Zi = point_cloud_face[idx + 2];
1251 
1252  error += vpMath::sqr(A * xi + B * yi + C - 1 / Zi);
1253  residues[idx / 3] = (A * xi + B * yi + C - 1 / Zi);
1254  }
1255 
1256  error /= point_cloud_face.size() / 3;
1257 
1258  iter++;
1259  } // while ( std::fabs(error - prev_error) > 1e-6 && (iter < max_iter) )
1260 #endif
1261  } else {
1262  while (std::fabs(error - prev_error) > 1e-6 && (iter < max_iter)) {
1263  if (iter == 0) {
1264  // Transform the plane equation for the current pose
1267 
1268  double ux = m_planeCamera.getA();
1269  double uy = m_planeCamera.getB();
1270  double uz = m_planeCamera.getC();
1271  double D = m_planeCamera.getD();
1272 
1273  // Features
1274  A = -ux / D;
1275  B = -uy / D;
1276  C = -uz / D;
1277 
1278  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1279  double xi = point_cloud_face[3 * i];
1280  double yi = point_cloud_face[3 * i + 1];
1281  double Zi = point_cloud_face[3 * i + 2];
1282 
1283  residues[i] = (A * xi + B * yi + C - 1 / Zi);
1284  }
1285  }
1286 
1287  tukey_robust.MEstimator(residues, w, 1e-2);
1288 
1289  // Estimate A, B, C
1290  double sum_wi2_xi2 = 0.0, sum_wi2_yi2 = 0.0, sum_wi2 = 0.0;
1291  double sum_wi2_xi_yi = 0.0, sum_wi2_xi = 0.0, sum_wi2_yi = 0.0;
1292 
1293  double sum_wi2_xi_Zi = 0.0, sum_wi2_yi_Zi = 0.0, sum_wi2_Zi = 0.0;
1294 
1295  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1296  double wi2 = w[i] * w[i];
1297 
1298  double xi = point_cloud_face[3 * i];
1299  double yi = point_cloud_face[3 * i + 1];
1300  double Zi = point_cloud_face[3 * i + 2];
1301  double invZi = 1 / Zi;
1302 
1303  sum_wi2_xi2 += wi2 * xi * xi;
1304  sum_wi2_yi2 += wi2 * yi * yi;
1305  sum_wi2 += wi2;
1306  sum_wi2_xi_yi += wi2 * xi * yi;
1307  sum_wi2_xi += wi2 * xi;
1308  sum_wi2_yi += wi2 * yi;
1309 
1310  sum_wi2_xi_Zi += wi2 * xi * invZi;
1311  sum_wi2_yi_Zi += wi2 * yi * invZi;
1312  sum_wi2_Zi += wi2 * invZi;
1313  }
1314 
1315  ATA_3x3[0] = sum_wi2_xi2;
1316  ATA_3x3[1] = sum_wi2_xi_yi;
1317  ATA_3x3[2] = sum_wi2_xi;
1318  ATA_3x3[3] = sum_wi2_xi_yi;
1319  ATA_3x3[4] = sum_wi2_yi2;
1320  ATA_3x3[5] = sum_wi2_yi;
1321  ATA_3x3[6] = sum_wi2_xi;
1322  ATA_3x3[7] = sum_wi2_yi;
1323  ATA_3x3[8] = sum_wi2;
1324 
1325  Mat33<double> minv = ATA_3x3.inverse();
1326 
1327  A = minv[0] * sum_wi2_xi_Zi + minv[1] * sum_wi2_yi_Zi + minv[2] * sum_wi2_Zi;
1328  B = minv[3] * sum_wi2_xi_Zi + minv[4] * sum_wi2_yi_Zi + minv[5] * sum_wi2_Zi;
1329  C = minv[6] * sum_wi2_xi_Zi + minv[7] * sum_wi2_yi_Zi + minv[8] * sum_wi2_Zi;
1330 
1331  prev_error = error;
1332  error = 0.0;
1333 
1334  // Compute error
1335  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1336  double xi = point_cloud_face[3 * i];
1337  double yi = point_cloud_face[3 * i + 1];
1338  double Zi = point_cloud_face[3 * i + 2];
1339 
1340  error += vpMath::sqr(A * xi + B * yi + C - 1 / Zi);
1341  residues[i] = (A * xi + B * yi + C - 1 / Zi);
1342  }
1343 
1344  error /= point_cloud_face.size() / 3;
1345 
1346  iter++;
1347  } // while ( std::fabs(error - prev_error) > 1e-6 && (iter < max_iter) )
1348  }
1349 
1350  x_estimated.resize(3, false);
1351  x_estimated[0] = A;
1352  x_estimated[1] = B;
1353  x_estimated[2] = C;
1354 }
1355 
1356 void vpMbtFaceDepthNormal::estimatePlaneEquationSVD(const std::vector<double> &point_cloud_face,
1357  const vpHomogeneousMatrix &cMo,
1358  vpColVector &plane_equation_estimated, vpColVector &centroid)
1359 {
1360  const unsigned int max_iter = 10;
1361  double prev_error = 1e3;
1362  double error = 1e3 - 1;
1363 
1364  std::vector<double> weights(point_cloud_face.size() / 3, 1.0);
1365  std::vector<double> residues(point_cloud_face.size() / 3);
1366  vpMatrix M((unsigned int)(point_cloud_face.size() / 3), 3);
1367  vpMbtTukeyEstimator<double> tukey;
1368  vpColVector normal;
1369 
1370  for (unsigned int iter = 0; iter < max_iter && std::fabs(error - prev_error) > 1e-6; iter++) {
1371  if (iter != 0) {
1372  tukey.MEstimator(residues, weights, 1e-4);
1373  } else {
1374  // Transform the plane equation for the current pose
1377 
1378  double A = m_planeCamera.getA();
1379  double B = m_planeCamera.getB();
1380  double C = m_planeCamera.getC();
1381  double D = m_planeCamera.getD();
1382 
1383  // Compute distance point to estimated plane
1384  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1385  residues[i] = std::fabs(A * point_cloud_face[3 * i] + B * point_cloud_face[3 * i + 1] +
1386  C * point_cloud_face[3 * i + 2] + D) /
1387  sqrt(A * A + B * B + C * C);
1388  }
1389 
1390  tukey.MEstimator(residues, weights, 1e-4);
1391  plane_equation_estimated.resize(4, false);
1392  }
1393 
1394  // Compute centroid
1395  double centroid_x = 0.0, centroid_y = 0.0, centroid_z = 0.0;
1396  double total_w = 0.0;
1397 
1398  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1399  centroid_x += weights[i] * point_cloud_face[3 * i];
1400  centroid_y += weights[i] * point_cloud_face[3 * i + 1];
1401  centroid_z += weights[i] * point_cloud_face[3 * i + 2];
1402  total_w += weights[i];
1403  }
1404 
1405  centroid_x /= total_w;
1406  centroid_y /= total_w;
1407  centroid_z /= total_w;
1408 
1409  // Minimization
1410  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1411  M[(unsigned int)i][0] = weights[i] * (point_cloud_face[3 * i] - centroid_x);
1412  M[(unsigned int)i][1] = weights[i] * (point_cloud_face[3 * i + 1] - centroid_y);
1413  M[(unsigned int)i][2] = weights[i] * (point_cloud_face[3 * i + 2] - centroid_z);
1414  }
1415 
1416  vpMatrix J = M.t() * M;
1417 
1418  vpColVector W;
1419  vpMatrix V;
1420  J.svd(W, V);
1421 
1422  double smallestSv = W[0];
1423  unsigned int indexSmallestSv = 0;
1424  for (unsigned int i = 1; i < W.size(); i++) {
1425  if (W[i] < smallestSv) {
1426  smallestSv = W[i];
1427  indexSmallestSv = i;
1428  }
1429  }
1430 
1431  normal = V.getCol(indexSmallestSv);
1432 
1433  // Compute plane equation
1434  double A = normal[0], B = normal[1], C = normal[2];
1435  double D = -(A * centroid_x + B * centroid_y + C * centroid_z);
1436 
1437  // Update plane equation
1438  plane_equation_estimated[0] = A;
1439  plane_equation_estimated[1] = B;
1440  plane_equation_estimated[2] = C;
1441  plane_equation_estimated[3] = D;
1442 
1443  // Compute error points to estimated plane
1444  prev_error = error;
1445  error = 0.0;
1446  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1447  residues[i] = std::fabs(A * point_cloud_face[3 * i] + B * point_cloud_face[3 * i + 1] +
1448  C * point_cloud_face[3 * i + 2] + D) /
1449  sqrt(A * A + B * B + C * C);
1450  error += residues[i] * residues[i];
1451  }
1452  error /= sqrt(error / total_w);
1453  }
1454 
1455  // Update final weights
1456  tukey.MEstimator(residues, weights, 1e-4);
1457 
1458  // Update final centroid
1459  centroid.resize(3, false);
1460  double total_w = 0.0;
1461 
1462  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1463  centroid[0] += weights[i] * point_cloud_face[3 * i];
1464  centroid[1] += weights[i] * point_cloud_face[3 * i + 1];
1465  centroid[2] += weights[i] * point_cloud_face[3 * i + 2];
1466  total_w += weights[i];
1467  }
1468 
1469  centroid[0] /= total_w;
1470  centroid[1] /= total_w;
1471  centroid[2] /= total_w;
1472 
1473  // Compute final plane equation
1474  double A = normal[0], B = normal[1], C = normal[2];
1475  double D = -(A * centroid[0] + B * centroid[1] + C * centroid[2]);
1476 
1477  // Update final plane equation
1478  plane_equation_estimated[0] = A;
1479  plane_equation_estimated[1] = B;
1480  plane_equation_estimated[2] = C;
1481  plane_equation_estimated[3] = D;
1482 }
1483 
1493 bool vpMbtFaceDepthNormal::samePoint(const vpPoint &P1, const vpPoint &P2) const
1494 {
1495  double dx = fabs(P1.get_oX() - P2.get_oX());
1496  double dy = fabs(P1.get_oY() - P2.get_oY());
1497  double dz = fabs(P1.get_oZ() - P2.get_oZ());
1498 
1499  if (dx <= std::numeric_limits<double>::epsilon() && dy <= std::numeric_limits<double>::epsilon() &&
1500  dz <= std::numeric_limits<double>::epsilon())
1501  return true;
1502  else
1503  return false;
1504 }
1505 
1507 {
1508  m_cam = camera;
1509 
1510  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
1511  ++it) {
1512  (*it)->setCameraParameters(camera);
1513  }
1514 }
1515 
1517 {
1518  m_useScanLine = v;
1519 
1520  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
1521  ++it) {
1522  (*it)->useScanLine = v;
1523  }
1524 }
vpFeatureEstimationType m_featureEstimationMethod
Method to estimate the desired features.
void svd(vpColVector &w, vpMatrix &V)
Definition: vpMatrix.cpp:1791
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:104
double getTop() const
Definition: vpRect.h:175
void getRoiClipped(const vpCameraParameters &cam, std::vector< vpImagePoint > &roi)
bool computeDesiredFeatures(const vpHomogeneousMatrix &cMo, const unsigned int width, const unsigned int height, const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &point_cloud, vpColVector &desired_features, const unsigned int stepX, const unsigned int stepY)
double get_oY() const
Get the point Y coordinate in the object frame.
Definition: vpPoint.cpp:422
Implements a 3D polygon with render functionnalities like clipping.
Definition: vpPolygon3D.h:59
void setVisible(bool _isvisible)
int getIndex() const
Definition: vpMbtPolygon.h:101
void display(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const vpColor &col, const unsigned int thickness=1, const bool displayFullModel=false)
Implementation of an homogeneous matrix and operations on such kind of matrices.
std::list< int > Lindex_polygon
Index of the faces which contain the line.
void setFarClippingDistance(const double &dist)
Definition: vpPolygon3D.h:194
int m_pclPlaneEstimationMethod
PCL plane estimation method.
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
Point coordinates conversion from normalized coordinates in meter to pixel coordinates ...
void resize(const unsigned int nrows, const unsigned int ncols, const bool flagNullify=true, const bool recopy_=true)
Definition: vpArray2D.h:171
unsigned int m_clippingFlag
Flags specifying which clipping to used.
Class to define colors available for display functionnalities.
Definition: vpColor.h:120
void setLeft(double pos)
Definition: vpRect.h:257
int m_pclPlaneEstimationRansacMaxIter
PCL pane estimation max number of iterations.
vpPoint * p1
The first extremity.
void computeDesiredFeaturesRobustFeatures(const std::vector< double > &point_cloud_face_custom, const std::vector< double > &point_cloud_face, const vpHomogeneousMatrix &cMo, vpColVector &desired_features, vpColVector &desired_normal, vpColVector &centroid_point)
error that can be emited by ViSP classes.
Definition: vpException.h:71
vpMbScanLine & getMbScanLineRenderer()
vpHomogeneousMatrix inverse() const
Manage the line of a polygon used in the model-based tracker.
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Point coordinates conversion from pixel coordinates to normalized coordinates in meter...
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:158
double m_distNearClip
Distance for near clipping.
void addLine(vpPoint &p1, vpPoint &p2, vpMbHiddenFaces< vpMbtPolygon > *const faces, int polygon=-1, std::string name="")
void set_X(const double X)
Set the point X coordinate in the camera frame.
Definition: vpPoint.cpp:452
vpMbtPolygon & getPolygon()
bool samePoint(const vpPoint &P1, const vpPoint &P2) const
double get_oX() const
Get the point X coordinate in the object frame.
Definition: vpPoint.cpp:420
bool m_useScanLine
Scan line visibility.
double getRight() const
Definition: vpRect.h:162
vpCameraParameters m_cam
Camera intrinsic parameters.
vpRect getBoundingBox() const
Definition: vpPolygon.h:177
static const vpColor red
Definition: vpColor.h:180
Class that defines what is a point.
Definition: vpPoint.h:58
void computeROI(const vpHomogeneousMatrix &cMo, const unsigned int width, const unsigned int height, std::vector< vpImagePoint > &roiPts)
void setScanLineVisibilityTest(const bool v)
bool computePolygonCentroid(const std::vector< vpPoint > &points, vpPoint &centroid)
void setCameraParameters(const vpCameraParameters &camera)
bool m_faceActivated
True if the face should be considered by the tracker.
vpMbtPolygon * m_polygon
Polygon defining the face.
Defines a generic 2D polygon.
Definition: vpPolygon.h:103
vpMatrix t() const
Definition: vpMatrix.cpp:375
vpColVector & normalize()
void set_Z(const double Z)
Set the point Z coordinate in the camera frame.
Definition: vpPoint.cpp:456
void setTop(double pos)
Definition: vpRect.h:292
void computeInteractionMatrix(const vpHomogeneousMatrix &cMo, vpMatrix &L, vpColVector &features)
double getWidth() const
Definition: vpRect.h:197
double getD() const
Definition: vpPlane.h:108
vpPoint * p2
The second extremity.
void changeFrame(const vpHomogeneousMatrix &cMo)
Definition: vpPlane.cpp:354
static void displayArrow(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1)
static double sqr(double x)
Definition: vpMath.h:108
bool computeDesiredFeaturesPCL(const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &point_cloud_face, vpColVector &desired_features, vpColVector &desired_normal, vpColVector &centroid_point)
VISP_EXPORT bool checkSSE2()
double getB() const
Definition: vpPlane.h:104
bool isInside(const vpImagePoint &iP, const PointInPolygonMethod &method=PnPolyRayCasting) const
Definition: vpPolygon.cpp:317
void getPolygonClipped(std::vector< std::pair< vpPoint, unsigned int > > &poly)
vpMbHiddenFaces< vpMbtPolygon > * m_hiddenFace
Pointer to the list of faces.
Generic class defining intrinsic camera parameters.
void setIndex(const unsigned int i)
void set_Y(const double Y)
Set the point Y coordinate in the camera frame.
Definition: vpPoint.cpp:454
double get_oZ() const
Get the point Z coordinate in the object frame.
Definition: vpPoint.cpp:424
vpPoint m_faceDesiredNormal
Face (normalized) normal (computed from the sensor)
double getLeft() const
Definition: vpRect.h:156
virtual bool isVisible(const vpHomogeneousMatrix &cMo, const double alpha, const bool &modulo=false, const vpCameraParameters &cam=vpCameraParameters(), const vpImage< unsigned char > &I=vpImage< unsigned char >())
double m_distFarClip
Distance for near clipping.
std::vector< vpMbtDistanceLine * > m_listOfFaceLines
void displayFeature(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const double scale=0.05, const unsigned int thickness=1)
void setClipping(const unsigned int &flags)
Definition: vpPolygon3D.h:187
std::vector< PolygonLine > m_polygonLines
double getA() const
Definition: vpPlane.h:102
vpFaceCentroidType m_faceCentroidMethod
Method to compute the face centroid for the current features.
void setName(const std::string &line_name)
void setCameraParameters(const vpCameraParameters &camera)
double get_X() const
Get the point X coordinate in the camera frame.
Definition: vpPoint.cpp:411
void computeScanLineQuery(const vpPoint &a, const vpPoint &b, std::vector< std::pair< vpPoint, vpPoint > > &lines, const bool &displayResults=false)
void setWorldCoordinates(const double oX, const double oY, const double oZ)
Definition: vpPoint.cpp:113
void estimatePlaneEquationSVD(const std::vector< double > &point_cloud_face, const vpHomogeneousMatrix &cMo, vpColVector &plane_equation_estimated, vpColVector &centroid)
unsigned int getHeight() const
Definition: vpImage.h:178
void computeDesiredFeaturesSVD(const std::vector< double > &point_cloud_face, const vpHomogeneousMatrix &cMo, vpColVector &desired_features, vpColVector &desired_normal, vpColVector &centroid_point)
void computeDesiredNormalAndCentroid(const vpHomogeneousMatrix &cMo, const vpColVector &desired_normal, const vpColVector &centroid_point)
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
static double dotProd(const vpColVector &a, const vpColVector &b)
double get_x() const
Get the point x coordinate in the image plane.
Definition: vpPoint.cpp:429
void setRight(double pos)
Definition: vpRect.h:283
vpMbHiddenFaces< vpMbtPolygon > * hiddenface
Pointer to the list of faces.
double getHeight() const
Definition: vpRect.h:149
double get_y() const
Get the point y coordinate in the image plane.
Definition: vpPoint.cpp:431
bool isVisible(const unsigned int i)
double getC() const
Definition: vpPlane.h:106
void addPolygon(const int &index)
void setNearClippingDistance(const double &dist)
Definition: vpPolygon3D.h:207
vpPoint m_faceDesiredCentroid
Desired centroid (computed from the sensor)
Defines a rectangle in the plane.
Definition: vpRect.h:78
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
Compute the geometric centroid.
double get_Z() const
Get the point Z coordinate in the camera frame.
Definition: vpPoint.cpp:415
vpPlane m_planeObject
Plane equation described in the object frame.
void changeFrame(const vpHomogeneousMatrix &cMo, vpColVector &_cP)
Definition: vpPoint.cpp:233
double get_Y() const
Get the point Y coordinate in the camera frame.
Definition: vpPoint.cpp:413
vpColVector getCol(const unsigned int j) const
Definition: vpMatrix.cpp:3797
void estimateFeatures(const std::vector< double > &point_cloud_face, const vpHomogeneousMatrix &cMo, vpColVector &x_estimated, std::vector< double > &weights)
unsigned int getWidth() const
Definition: vpImage.h:229
double getBottom() const
Definition: vpRect.h:94
void setBottom(double pos)
Definition: vpRect.h:224
void display(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const vpColor &col, const unsigned int thickness=1, const bool displayFullModel=false)
bool useScanLine
Use scanline rendering.
void buildFrom(vpPoint &_p1, vpPoint &_p2)
static const vpColor blue
Definition: vpColor.h:186
void computeNormalVisibility(const double nx, const double ny, const double nz, const vpColVector &centroid_point, vpColVector &face_normal)
double m_pclPlaneEstimationRansacThreshold
PCL plane estimation RANSAC threshold.
void resize(const unsigned int i, const bool flagNullify=true)
Definition: vpColVector.h:241
void computeFov(const unsigned int &w, const unsigned int &h)