Visual Servoing Platform  version 3.6.1 under development (2024-11-14)
vpMbtFaceDepthNormal.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 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 https://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 #if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_SEGMENTATION) && defined(VISP_HAVE_PCL_FILTERS) && defined(VISP_HAVE_PCL_COMMON)
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 
58 BEGIN_VISP_NAMESPACE
60  : m_cam(), m_clippingFlag(vpPolygon3D::NO_CLIPPING), m_distFarClip(100), m_distNearClip(0.001), m_hiddenFace(nullptr),
61  m_planeObject(), m_polygon(nullptr), m_useScanLine(false), m_faceActivated(false),
62  m_faceCentroidMethod(GEOMETRIC_CENTROID), m_faceDesiredCentroid(), m_faceDesiredNormal(),
63  m_featureEstimationMethod(ROBUST_FEATURE_ESTIMATION), m_isTrackedDepthNormalFace(true), m_isVisible(false),
64  m_listOfFaceLines(), m_planeCamera(),
65  m_pclPlaneEstimationMethod(2), // SAC_MSAC, see pcl/sample_consensus/method_types.h
66  m_pclPlaneEstimationRansacMaxIter(200), m_pclPlaneEstimationRansacThreshold(0.001), m_polygonLines()
67 { }
68 
70 {
71  for (size_t i = 0; i < m_listOfFaceLines.size(); i++) {
72  delete m_listOfFaceLines[i];
73  }
74 }
75 
91  vpUniRand &rand_gen, int polygon, std::string name)
92 {
93  // Build a PolygonLine to be able to easily display the lines model
94  PolygonLine polygon_line;
95 
96  // Add polygon
97  polygon_line.m_poly.setNbPoint(2);
98  polygon_line.m_poly.addPoint(0, P1);
99  polygon_line.m_poly.addPoint(1, P2);
100 
101  polygon_line.m_poly.setClipping(m_clippingFlag);
102  polygon_line.m_poly.setNearClippingDistance(m_distNearClip);
103  polygon_line.m_poly.setFarClippingDistance(m_distFarClip);
104 
105  polygon_line.m_p1 = &polygon_line.m_poly.p[0];
106  polygon_line.m_p2 = &polygon_line.m_poly.p[1];
107 
108  m_polygonLines.push_back(polygon_line);
109 
110  // suppress line already in the model
111  bool already_here = false;
113 
114  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
115  ++it) {
116  l = *it;
117  if ((samePoint(*(l->p1), P1) && samePoint(*(l->p2), P2)) || (samePoint(*(l->p1), P2) && samePoint(*(l->p2), P1))) {
118  already_here = true;
119  l->addPolygon(polygon);
120  l->hiddenface = faces;
122  }
123  }
124 
125  if (!already_here) {
126  l = new vpMbtDistanceLine;
127 
129  l->buildFrom(P1, P2, rand_gen);
130  l->addPolygon(polygon);
131  l->hiddenface = faces;
133 
134  l->setIndex((unsigned int)m_listOfFaceLines.size());
135  l->setName(name);
136 
139 
142 
145 
146  m_listOfFaceLines.push_back(l);
147  }
148 }
149 
150 #if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_SEGMENTATION) && defined(VISP_HAVE_PCL_FILTERS) && defined(VISP_HAVE_PCL_COMMON)
152  unsigned int height,
153  const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &point_cloud,
154  vpColVector &desired_features, unsigned int stepX, unsigned int stepY
155 #if DEBUG_DISPLAY_DEPTH_NORMAL
156  ,
157  vpImage<unsigned char> &debugImage,
158  std::vector<std::vector<vpImagePoint> > &roiPts_vec
159 #endif
160  ,
161  const vpImage<bool> *mask)
162 {
163  m_faceActivated = false;
164 
165  if (width == 0 || height == 0)
166  return false;
167 
168  std::vector<vpImagePoint> roiPts;
169  vpColVector desired_normal(3);
170 
171  computeROI(cMo, width, height, roiPts
172 #if DEBUG_DISPLAY_DEPTH_NORMAL
173  ,
174  roiPts_vec
175 #endif
176  );
177 
178  if (roiPts.size() <= 2) {
179 #ifndef NDEBUG
180  std::cerr << "Error: roiPts.size() <= 2 in computeDesiredFeatures" << std::endl;
181 #endif
182  return false;
183  }
184 
185  vpPolygon polygon_2d(roiPts);
186  vpRect bb = polygon_2d.getBoundingBox();
187 
188  unsigned int top = (unsigned int)std::max<double>(0.0, bb.getTop());
189  unsigned int bottom = (unsigned int)std::min<double>((double)height, std::max<double>(0.0, bb.getBottom()));
190  unsigned int left = (unsigned int)std::max<double>(0.0, bb.getLeft());
191  unsigned int right = (unsigned int)std::min<double>((double)width, std::max<double>(0.0, bb.getRight()));
192 
193  bb.setTop(top);
194  bb.setBottom(bottom);
195  bb.setLeft(left);
196  bb.setRight(right);
197 
198  // Keep only 3D points inside the projected polygon face
199  pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_face(new pcl::PointCloud<pcl::PointXYZ>);
200  std::vector<double> point_cloud_face_vec, point_cloud_face_custom;
201 
203  point_cloud_face_custom.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
204  point_cloud_face_vec.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
205  }
207  point_cloud_face_vec.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
208  }
210  point_cloud_face->reserve((size_t)(bb.getWidth() * bb.getHeight()));
211  }
212 
213  bool checkSSE2 = vpCPUFeatures::checkSSE2();
214 #if !USE_SSE
215  checkSSE2 = false;
216 #else
217  bool push = false;
218  double prev_x, prev_y, prev_z;
219 #endif
220 
221  double x = 0.0, y = 0.0;
222  for (unsigned int i = top; i < bottom; i += stepY) {
223  for (unsigned int j = left; j < right; j += stepX) {
224  if (vpMeTracker::inRoiMask(mask, i, j) && pcl::isFinite((*point_cloud)(j, i)) && (*point_cloud)(j, i).z > 0 &&
225  (m_useScanLine ? (i < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getHeight() &&
226  j < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getWidth() &&
227  m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs()[i][j] == m_polygon->getIndex())
228  : polygon_2d.isInside(vpImagePoint(i, j)))) {
229 
231  point_cloud_face->push_back((*point_cloud)(j, i));
232  }
235  point_cloud_face_vec.push_back((*point_cloud)(j, i).x);
236  point_cloud_face_vec.push_back((*point_cloud)(j, i).y);
237  point_cloud_face_vec.push_back((*point_cloud)(j, i).z);
238 
240  // Add point for custom method for plane equation estimation
242 
243  if (checkSSE2) {
244 #if USE_SSE
245  if (!push) {
246  push = true;
247  prev_x = x;
248  prev_y = y;
249  prev_z = (*point_cloud)(j, i).z;
250  }
251  else {
252  push = false;
253  point_cloud_face_custom.push_back(prev_x);
254  point_cloud_face_custom.push_back(x);
255 
256  point_cloud_face_custom.push_back(prev_y);
257  point_cloud_face_custom.push_back(y);
258 
259  point_cloud_face_custom.push_back(prev_z);
260  point_cloud_face_custom.push_back((*point_cloud)(j, i).z);
261  }
262 #endif
263  }
264  else {
265  point_cloud_face_custom.push_back(x);
266  point_cloud_face_custom.push_back(y);
267  point_cloud_face_custom.push_back((*point_cloud)(j, i).z);
268  }
269  }
270  }
271 
272 #if DEBUG_DISPLAY_DEPTH_NORMAL
273  debugImage[i][j] = 255;
274 #endif
275  }
276  }
277  }
278 
279 #if USE_SSE
280  if (checkSSE2 && push) {
281  point_cloud_face_custom.push_back(prev_x);
282  point_cloud_face_custom.push_back(prev_y);
283  point_cloud_face_custom.push_back(prev_z);
284  }
285 #endif
286 
287  if (point_cloud_face->empty() && point_cloud_face_custom.empty() && point_cloud_face_vec.empty()) {
288  return false;
289  }
290 
291  // Face centroid computed by the different methods
292  vpColVector centroid_point(3);
293 
295  if (!computeDesiredFeaturesPCL(point_cloud_face, desired_features, desired_normal, centroid_point)) {
296  return false;
297  }
298  }
300  computeDesiredFeaturesSVD(point_cloud_face_vec, cMo, desired_features, desired_normal, centroid_point);
301  }
303  computeDesiredFeaturesRobustFeatures(point_cloud_face_custom, point_cloud_face_vec, cMo, desired_features,
304  desired_normal, centroid_point);
305  }
306  else {
307  throw vpException(vpException::badValue, "Unknown feature estimation method!");
308  }
309 
310  computeDesiredNormalAndCentroid(cMo, desired_normal, centroid_point);
311 
312  m_faceActivated = true;
313 
314  return true;
315 }
316 #endif
317 
319  unsigned int height, const std::vector<vpColVector> &point_cloud,
320  vpColVector &desired_features, unsigned int stepX, unsigned int stepY
321 #if DEBUG_DISPLAY_DEPTH_NORMAL
322  ,
323  vpImage<unsigned char> &debugImage,
324  std::vector<std::vector<vpImagePoint> > &roiPts_vec
325 #endif
326  ,
327  const vpImage<bool> *mask)
328 {
329  m_faceActivated = false;
330 
331  if (width == 0 || height == 0)
332  return false;
333 
334  std::vector<vpImagePoint> roiPts;
335  vpColVector desired_normal(3);
336 
337  computeROI(cMo, width, height, roiPts
338 #if DEBUG_DISPLAY_DEPTH_NORMAL
339  ,
340  roiPts_vec
341 #endif
342  );
343 
344  if (roiPts.size() <= 2) {
345 #ifndef NDEBUG
346  std::cerr << "Error: roiPts.size() <= 2 in computeDesiredFeatures" << std::endl;
347 #endif
348  return false;
349  }
350 
351  vpPolygon polygon_2d(roiPts);
352  vpRect bb = polygon_2d.getBoundingBox();
353 
354  unsigned int top = (unsigned int)std::max<double>(0.0, bb.getTop());
355  unsigned int bottom = (unsigned int)std::min<double>((double)height, std::max<double>(0.0, bb.getBottom()));
356  unsigned int left = (unsigned int)std::max<double>(0.0, bb.getLeft());
357  unsigned int right = (unsigned int)std::min<double>((double)width, std::max<double>(0.0, bb.getRight()));
358 
359  bb.setTop(top);
360  bb.setBottom(bottom);
361  bb.setLeft(left);
362  bb.setRight(right);
363 
364  // Keep only 3D points inside the projected polygon face
365  std::vector<double> point_cloud_face, point_cloud_face_custom;
366 
367  point_cloud_face.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
369  point_cloud_face_custom.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
370  }
371 
372  bool checkSSE2 = vpCPUFeatures::checkSSE2();
373 #if !USE_SSE
374  checkSSE2 = false;
375 #else
376  bool push = false;
377  double prev_x, prev_y, prev_z;
378 #endif
379 
380  double x = 0.0, y = 0.0;
381  for (unsigned int i = top; i < bottom; i += stepY) {
382  for (unsigned int j = left; j < right; j += stepX) {
383  if (vpMeTracker::inRoiMask(mask, i, j) && point_cloud[i * width + j][2] > 0 &&
384  (m_useScanLine ? (i < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getHeight() &&
385  j < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getWidth() &&
386  m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs()[i][j] == m_polygon->getIndex())
387  : polygon_2d.isInside(vpImagePoint(i, j)))) {
388 // Add point
389  point_cloud_face.push_back(point_cloud[i * width + j][0]);
390  point_cloud_face.push_back(point_cloud[i * width + j][1]);
391  point_cloud_face.push_back(point_cloud[i * width + j][2]);
392 
394  // Add point for custom method for plane equation estimation
396 
397  if (checkSSE2) {
398 #if USE_SSE
399  if (!push) {
400  push = true;
401  prev_x = x;
402  prev_y = y;
403  prev_z = point_cloud[i * width + j][2];
404  }
405  else {
406  push = false;
407  point_cloud_face_custom.push_back(prev_x);
408  point_cloud_face_custom.push_back(x);
409 
410  point_cloud_face_custom.push_back(prev_y);
411  point_cloud_face_custom.push_back(y);
412 
413  point_cloud_face_custom.push_back(prev_z);
414  point_cloud_face_custom.push_back(point_cloud[i * width + j][2]);
415  }
416 #endif
417  }
418  else {
419  point_cloud_face_custom.push_back(x);
420  point_cloud_face_custom.push_back(y);
421  point_cloud_face_custom.push_back(point_cloud[i * width + j][2]);
422  }
423  }
424 
425 #if DEBUG_DISPLAY_DEPTH_NORMAL
426  debugImage[i][j] = 255;
427 #endif
428  }
429  }
430  }
431 
432 #if USE_SSE
433  if (checkSSE2 && push) {
434  point_cloud_face_custom.push_back(prev_x);
435  point_cloud_face_custom.push_back(prev_y);
436  point_cloud_face_custom.push_back(prev_z);
437  }
438 #endif
439 
440  if (point_cloud_face.empty() && point_cloud_face_custom.empty()) {
441  return false;
442  }
443 
444  // Face centroid computed by the different methods
445  vpColVector centroid_point(3);
446 
447 #if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_SEGMENTATION) && defined(VISP_HAVE_PCL_FILTERS) && defined(VISP_HAVE_PCL_COMMON)
449  pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_face_pcl(new pcl::PointCloud<pcl::PointXYZ>);
450  point_cloud_face_pcl->reserve(point_cloud_face.size() / 3);
451 
452  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
453  point_cloud_face_pcl->push_back(
454  pcl::PointXYZ(point_cloud_face[3 * i], point_cloud_face[3 * i + 1], point_cloud_face[3 * i + 2]));
455  }
456 
457  computeDesiredFeaturesPCL(point_cloud_face_pcl, desired_features, desired_normal, centroid_point);
458  }
459  else
460 #endif
462  computeDesiredFeaturesSVD(point_cloud_face, cMo, desired_features, desired_normal, centroid_point);
463  }
465  computeDesiredFeaturesRobustFeatures(point_cloud_face_custom, point_cloud_face, cMo, desired_features,
466  desired_normal, centroid_point);
467  }
468  else {
469  throw vpException(vpException::badValue, "Unknown feature estimation method!");
470  }
471 
472  computeDesiredNormalAndCentroid(cMo, desired_normal, centroid_point);
473 
474  m_faceActivated = true;
475 
476  return true;
477 }
478 
480  unsigned int height, const vpMatrix &point_cloud,
481  vpColVector &desired_features, unsigned int stepX, unsigned int stepY
482 #if DEBUG_DISPLAY_DEPTH_NORMAL
483  ,
484  vpImage<unsigned char> &debugImage,
485  std::vector<std::vector<vpImagePoint> > &roiPts_vec
486 #endif
487  ,
488  const vpImage<bool> *mask)
489 {
490  m_faceActivated = false;
491 
492  if (width == 0 || height == 0)
493  return false;
494 
495  std::vector<vpImagePoint> roiPts;
496  vpColVector desired_normal(3);
497 
498  computeROI(cMo, width, height, roiPts
499 #if DEBUG_DISPLAY_DEPTH_NORMAL
500  ,
501  roiPts_vec
502 #endif
503  );
504 
505  if (roiPts.size() <= 2) {
506 #ifndef NDEBUG
507  std::cerr << "Error: roiPts.size() <= 2 in computeDesiredFeatures" << std::endl;
508 #endif
509  return false;
510  }
511 
512  vpPolygon polygon_2d(roiPts);
513  vpRect bb = polygon_2d.getBoundingBox();
514 
515  unsigned int top = (unsigned int)std::max<double>(0.0, bb.getTop());
516  unsigned int bottom = (unsigned int)std::min<double>((double)height, std::max<double>(0.0, bb.getBottom()));
517  unsigned int left = (unsigned int)std::max<double>(0.0, bb.getLeft());
518  unsigned int right = (unsigned int)std::min<double>((double)width, std::max<double>(0.0, bb.getRight()));
519 
520  bb.setTop(top);
521  bb.setBottom(bottom);
522  bb.setLeft(left);
523  bb.setRight(right);
524 
525  // Keep only 3D points inside the projected polygon face
526  std::vector<double> point_cloud_face, point_cloud_face_custom;
527 
528  point_cloud_face.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
530  point_cloud_face_custom.reserve((size_t)(3 * bb.getWidth() * bb.getHeight()));
531  }
532 
533  bool checkSSE2 = vpCPUFeatures::checkSSE2();
534 #if !USE_SSE
535  checkSSE2 = false;
536 #else
537  bool push = false;
538  double prev_x, prev_y, prev_z;
539 #endif
540 
541  double x = 0.0, y = 0.0;
542  for (unsigned int i = top; i < bottom; i += stepY) {
543  for (unsigned int j = left; j < right; j += stepX) {
544  if (vpMeTracker::inRoiMask(mask, i, j) && point_cloud[i * width + j][2] > 0 &&
545  (m_useScanLine ? (i < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getHeight() &&
546  j < m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs().getWidth() &&
547  m_hiddenFace->getMbScanLineRenderer().getPrimitiveIDs()[i][j] == m_polygon->getIndex())
548  : polygon_2d.isInside(vpImagePoint(i, j)))) {
549 // Add point
550  point_cloud_face.push_back(point_cloud[i * width + j][0]);
551  point_cloud_face.push_back(point_cloud[i * width + j][1]);
552  point_cloud_face.push_back(point_cloud[i * width + j][2]);
553 
555  // Add point for custom method for plane equation estimation
557 
558  if (checkSSE2) {
559 #if USE_SSE
560  if (!push) {
561  push = true;
562  prev_x = x;
563  prev_y = y;
564  prev_z = point_cloud[i * width + j][2];
565  }
566  else {
567  push = false;
568  point_cloud_face_custom.push_back(prev_x);
569  point_cloud_face_custom.push_back(x);
570 
571  point_cloud_face_custom.push_back(prev_y);
572  point_cloud_face_custom.push_back(y);
573 
574  point_cloud_face_custom.push_back(prev_z);
575  point_cloud_face_custom.push_back(point_cloud[i * width + j][2]);
576  }
577 #endif
578  }
579  else {
580  point_cloud_face_custom.push_back(x);
581  point_cloud_face_custom.push_back(y);
582  point_cloud_face_custom.push_back(point_cloud[i * width + j][2]);
583  }
584  }
585 
586 #if DEBUG_DISPLAY_DEPTH_NORMAL
587  debugImage[i][j] = 255;
588 #endif
589  }
590  }
591  }
592 
593 #if USE_SSE
594  if (checkSSE2 && push) {
595  point_cloud_face_custom.push_back(prev_x);
596  point_cloud_face_custom.push_back(prev_y);
597  point_cloud_face_custom.push_back(prev_z);
598  }
599 #endif
600 
601  if (point_cloud_face.empty() && point_cloud_face_custom.empty()) {
602  return false;
603  }
604 
605  // Face centroid computed by the different methods
606  vpColVector centroid_point(3);
607 
608 #if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_SEGMENTATION) && defined(VISP_HAVE_PCL_FILTERS) && defined(VISP_HAVE_PCL_COMMON)
610  pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_face_pcl(new pcl::PointCloud<pcl::PointXYZ>);
611  point_cloud_face_pcl->reserve(point_cloud_face.size() / 3);
612 
613  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
614  point_cloud_face_pcl->push_back(
615  pcl::PointXYZ(point_cloud_face[3 * i], point_cloud_face[3 * i + 1], point_cloud_face[3 * i + 2]));
616  }
617 
618  computeDesiredFeaturesPCL(point_cloud_face_pcl, desired_features, desired_normal, centroid_point);
619  }
620  else
621 #endif
623  computeDesiredFeaturesSVD(point_cloud_face, cMo, desired_features, desired_normal, centroid_point);
624  }
626  computeDesiredFeaturesRobustFeatures(point_cloud_face_custom, point_cloud_face, cMo, desired_features,
627  desired_normal, centroid_point);
628  }
629  else {
630  throw vpException(vpException::badValue, "Unknown feature estimation method!");
631  }
632 
633  computeDesiredNormalAndCentroid(cMo, desired_normal, centroid_point);
634 
635  m_faceActivated = true;
636 
637  return true;
638 }
639 #if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_SEGMENTATION) && defined(VISP_HAVE_PCL_FILTERS) && defined(VISP_HAVE_PCL_COMMON)
640 bool vpMbtFaceDepthNormal::computeDesiredFeaturesPCL(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &point_cloud_face,
641  vpColVector &desired_features, vpColVector &desired_normal,
642  vpColVector &centroid_point)
643 {
644  try {
645  // Compute plane equation for this subset of point cloud
646  pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
647  pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
648  // Create the segmentation object
649  pcl::SACSegmentation<pcl::PointXYZ> seg;
650  // Optional
651  seg.setOptimizeCoefficients(true);
652  // Mandatory
653  seg.setModelType(pcl::SACMODEL_PLANE);
654  seg.setMethodType(m_pclPlaneEstimationMethod);
655  seg.setDistanceThreshold(m_pclPlaneEstimationRansacThreshold);
656  seg.setMaxIterations(m_pclPlaneEstimationRansacMaxIter);
657 
658  seg.setInputCloud(point_cloud_face);
659  seg.segment(*inliers, *coefficients);
660 
661  pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_face_extracted(new pcl::PointCloud<pcl::PointXYZ>);
662  // Create the filtering object
663  pcl::ExtractIndices<pcl::PointXYZ> extract;
664 
665  // Extract the inliers
666  extract.setInputCloud(point_cloud_face);
667  extract.setIndices(inliers);
668  extract.setNegative(false);
669  extract.filter(*point_cloud_face_extracted);
670 
671 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
672  pcl::PointXYZ centroid_point_pcl;
673  if (pcl::computeCentroid(*point_cloud_face_extracted, centroid_point_pcl)) {
674  pcl::PointXYZ face_normal;
675  computeNormalVisibility(coefficients->values[0], coefficients->values[1], coefficients->values[2],
676  centroid_point_pcl, face_normal);
677 
678  desired_features.resize(3, false);
679  desired_features[0] = -coefficients->values[0] / coefficients->values[3];
680  desired_features[1] = -coefficients->values[1] / coefficients->values[3];
681  desired_features[2] = -coefficients->values[2] / coefficients->values[3];
682 
683  desired_normal[0] = face_normal.x;
684  desired_normal[1] = face_normal.y;
685  desired_normal[2] = face_normal.z;
686 
687  centroid_point[0] = centroid_point_pcl.x;
688  centroid_point[1] = centroid_point_pcl.y;
689  centroid_point[2] = centroid_point_pcl.z;
690  }
691  else {
692  std::cerr << "Cannot compute centroid!" << std::endl;
693  return false;
694  }
695 #else
696  std::cerr << "Cannot compute centroid using PCL " << PCL_VERSION_PRETTY << "!" << std::endl;
697  return false;
698 #endif
699  }
700  catch (const pcl::PCLException &e) {
701  std::cerr << "Catch a PCL exception: " << e.what() << std::endl;
702  throw;
703  }
704 
705  return true;
706 }
707 #endif
708 
709 void vpMbtFaceDepthNormal::computeDesiredFeaturesRobustFeatures(const std::vector<double> &point_cloud_face_custom,
710  const std::vector<double> &point_cloud_face,
711  const vpHomogeneousMatrix &cMo,
712  vpColVector &desired_features,
713  vpColVector &desired_normal,
714  vpColVector &centroid_point)
715 {
716  std::vector<double> weights;
717  double den = 0.0;
718  estimateFeatures(point_cloud_face_custom, cMo, desired_features, weights);
719 
720  // Compute face centroid
721  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
722  centroid_point[0] += weights[i] * point_cloud_face[3 * i];
723  centroid_point[1] += weights[i] * point_cloud_face[3 * i + 1];
724  centroid_point[2] += weights[i] * point_cloud_face[3 * i + 2];
725 
726  den += weights[i];
727  }
728 
729  centroid_point[0] /= den;
730  centroid_point[1] /= den;
731  centroid_point[2] /= den;
732 
733  computeNormalVisibility(-desired_features[0], -desired_features[1], -desired_features[2], centroid_point,
734  desired_normal);
735 }
736 
737 void vpMbtFaceDepthNormal::computeDesiredFeaturesSVD(const std::vector<double> &point_cloud_face,
738  const vpHomogeneousMatrix &cMo, vpColVector &desired_features,
739  vpColVector &desired_normal, vpColVector &centroid_point)
740 {
741  vpColVector plane_equation_SVD;
742  estimatePlaneEquationSVD(point_cloud_face, cMo, plane_equation_SVD, centroid_point);
743 
744  desired_features.resize(3, false);
745  desired_features[0] = -plane_equation_SVD[0] / plane_equation_SVD[3];
746  desired_features[1] = -plane_equation_SVD[1] / plane_equation_SVD[3];
747  desired_features[2] = -plane_equation_SVD[2] / plane_equation_SVD[3];
748 
749  computeNormalVisibility(-desired_features[0], -desired_features[1], -desired_features[2], centroid_point,
750  desired_normal);
751 }
752 
754  const vpColVector &desired_normal,
755  const vpColVector &centroid_point)
756 {
757  // Compute desired centroid in the object frame
758  vpColVector centroid_cam(4);
759  centroid_cam[0] = centroid_point[0];
760  centroid_cam[1] = centroid_point[1];
761  centroid_cam[2] = centroid_point[2];
762  centroid_cam[3] = 1;
763 
764  vpColVector centroid_obj = cMo.inverse() * centroid_cam;
765  m_faceDesiredCentroid.setWorldCoordinates(centroid_obj[0], centroid_obj[1], centroid_obj[2]);
766 
767  // Compute desired face normal in the object frame
768  vpColVector face_normal_cam(4);
769  face_normal_cam[0] = desired_normal[0];
770  face_normal_cam[1] = desired_normal[1];
771  face_normal_cam[2] = desired_normal[2];
772  face_normal_cam[3] = 1;
773 
774  vpColVector face_normal_obj = cMo.inverse() * face_normal_cam;
775  m_faceDesiredNormal.setWorldCoordinates(face_normal_obj[0], face_normal_obj[1], face_normal_obj[2]);
776 }
777 
778 bool vpMbtFaceDepthNormal::computePolygonCentroid(const std::vector<vpPoint> &points_, vpPoint &centroid)
779 {
780  if (points_.empty()) {
781  return false;
782  }
783 
784  if (points_.size() < 2) {
785  centroid = points_[0];
786  return true;
787  }
788 
789  std::vector<vpPoint> points = points_;
790  points.push_back(points_.front());
791 
792  double A1 = 0.0, A2 = 0.0, c_x1 = 0.0, c_x2 = 0.0, c_y = 0.0, c_z = 0.0;
793 
794  for (size_t i = 0; i < points.size() - 1; i++) {
795  // projection onto xy plane
796  c_x1 += (points[i].get_X() + points[i + 1].get_X()) *
797  (points[i].get_X() * points[i + 1].get_Y() - points[i + 1].get_X() * points[i].get_Y());
798  c_y += (points[i].get_Y() + points[i + 1].get_Y()) *
799  (points[i].get_X() * points[i + 1].get_Y() - points[i + 1].get_X() * points[i].get_Y());
800  A1 += points[i].get_X() * points[i + 1].get_Y() - points[i + 1].get_X() * points[i].get_Y();
801 
802  // projection onto xz plane
803  c_x2 += (points[i].get_X() + points[i + 1].get_X()) *
804  (points[i].get_X() * points[i + 1].get_Z() - points[i + 1].get_X() * points[i].get_Z());
805  c_z += (points[i].get_Z() + points[i + 1].get_Z()) *
806  (points[i].get_X() * points[i + 1].get_Z() - points[i + 1].get_X() * points[i].get_Z());
807  A2 += points[i].get_X() * points[i + 1].get_Z() - points[i + 1].get_X() * points[i].get_Z();
808  }
809 
810  c_x1 /= 3.0 * A1;
811  c_y /= 3.0 * A1;
812  c_x2 /= 3.0 * A2;
813  c_z /= 3.0 * A2;
814 
815  if (A1 > A2) {
816  centroid.set_X(c_x1);
817  }
818  else {
819  centroid.set_X(c_x2);
820  }
821 
822  centroid.set_Y(c_y);
823  centroid.set_Z(c_z);
824 
825  return true;
826 }
827 
828 void vpMbtFaceDepthNormal::computeROI(const vpHomogeneousMatrix &cMo, unsigned int width, unsigned int height,
829  std::vector<vpImagePoint> &roiPts
830 #if DEBUG_DISPLAY_DEPTH_NORMAL
831  ,
832  std::vector<std::vector<vpImagePoint> > &roiPts_vec
833 #endif
834 )
835 {
836  if (m_useScanLine || m_clippingFlag > 2)
837  m_cam.computeFov(width, height);
838 
839  if (m_useScanLine) {
840  for (std::vector<PolygonLine>::iterator it = m_polygonLines.begin(); it != m_polygonLines.end(); ++it) {
841  it->m_p1->changeFrame(cMo);
842  it->m_p2->changeFrame(cMo);
843 
844  vpImagePoint ip1, ip2;
845 
846  it->m_poly.changeFrame(cMo);
847  it->m_poly.computePolygonClipped(m_cam);
848 
849  if (it->m_poly.polyClipped.size() == 2 &&
850  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::NEAR_CLIPPING) == 0) &&
851  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::FAR_CLIPPING) == 0) &&
852  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::DOWN_CLIPPING) == 0) &&
853  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::UP_CLIPPING) == 0) &&
854  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::LEFT_CLIPPING) == 0) &&
855  ((it->m_poly.polyClipped[1].second & it->m_poly.polyClipped[0].second & vpPolygon3D::RIGHT_CLIPPING) == 0)) {
856 
857  std::vector<std::pair<vpPoint, vpPoint> > linesLst;
858  m_hiddenFace->computeScanLineQuery(it->m_poly.polyClipped[0].first, it->m_poly.polyClipped[1].first, linesLst,
859  true);
860 
861  for (unsigned int i = 0; i < linesLst.size(); i++) {
862  linesLst[i].first.project();
863  linesLst[i].second.project();
864 
865  vpMeterPixelConversion::convertPoint(m_cam, linesLst[i].first.get_x(), linesLst[i].first.get_y(), ip1);
866  vpMeterPixelConversion::convertPoint(m_cam, linesLst[i].second.get_x(), linesLst[i].second.get_y(), ip2);
867 
868  it->m_imPt1 = ip1;
869  it->m_imPt2 = ip2;
870 
871  roiPts.push_back(ip1);
872  roiPts.push_back(ip2);
873 
874 #if DEBUG_DISPLAY_DEPTH_NORMAL
875  std::vector<vpImagePoint> roiPts_;
876  roiPts_.push_back(ip1);
877  roiPts_.push_back(ip2);
878  roiPts_vec.push_back(roiPts_);
879 #endif
880  }
881  }
882  }
883  }
884  else {
885  // Get polygon clipped
886  m_polygon->getRoiClipped(m_cam, roiPts, cMo);
887 
888 #if DEBUG_DISPLAY_DEPTH_NORMAL
889  roiPts_vec.push_back(roiPts);
890 #endif
891  }
892 }
893 
895 
897 {
898  // Compute lines visibility, only for display
899  vpMbtDistanceLine *line;
900  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
901  ++it) {
902  line = *it;
903  bool isvisible = false;
904 
905  for (std::list<int>::const_iterator itindex = line->Lindex_polygon.begin(); itindex != line->Lindex_polygon.end();
906  ++itindex) {
907  int index = *itindex;
908  if (index == -1) {
909  isvisible = true;
910  }
911  else {
912  if (line->hiddenface->isVisible((unsigned int)index)) {
913  isvisible = true;
914  }
915  }
916  }
917 
918  // Si la ligne n'appartient a aucune face elle est tout le temps visible
919  if (line->Lindex_polygon.empty())
920  isvisible = true; // Not sure that this can occur
921 
922  if (isvisible) {
923  line->setVisible(true);
924  }
925  else {
926  line->setVisible(false);
927  }
928  }
929 }
930 
931 void vpMbtFaceDepthNormal::computeNormalVisibility(double nx, double ny, double nz, const vpHomogeneousMatrix &cMo,
932  const vpCameraParameters &camera, vpColVector &correct_normal,
933  vpPoint &centroid)
934 {
935  vpColVector faceNormal(3);
936  faceNormal[0] = nx;
937  faceNormal[1] = ny;
938  faceNormal[2] = nz;
939  faceNormal.normalize();
940 
941  // Get polygon clipped
942  std::vector<vpImagePoint> roiPts;
943  m_polygon->getRoiClipped(camera, roiPts, cMo);
944 
945  std::vector<vpPoint> polyPts;
946  m_polygon->getPolygonClipped(polyPts);
947 
948  vpColVector e4(3);
950  computePolygonCentroid(polyPts, centroid);
951  centroid.project();
952 
953  e4[0] = -centroid.get_X();
954  e4[1] = -centroid.get_Y();
955  e4[2] = -centroid.get_Z();
956  e4.normalize();
957  }
958  else {
959  double centroid_x = 0.0;
960  double centroid_y = 0.0;
961  double centroid_z = 0.0;
962 
963  for (size_t i = 0; i < polyPts.size(); i++) {
964  centroid_x += polyPts[i].get_X();
965  centroid_y += polyPts[i].get_Y();
966  centroid_z += polyPts[i].get_Z();
967  }
968 
969  centroid_x /= polyPts.size();
970  centroid_y /= polyPts.size();
971  centroid_z /= polyPts.size();
972 
973  e4[0] = -centroid_x;
974  e4[1] = -centroid_y;
975  e4[2] = -centroid_z;
976  e4.normalize();
977 
978  centroid.set_X(centroid_x);
979  centroid.set_Y(centroid_y);
980  centroid.set_Z(centroid_z);
981  }
982 
983  correct_normal.resize(3, false);
984  double angle = acos(vpColVector::dotProd(e4, faceNormal));
985  if (angle < M_PI_2) {
986  correct_normal = faceNormal;
987  }
988  else {
989  correct_normal[0] = -faceNormal[0];
990  correct_normal[1] = -faceNormal[1];
991  correct_normal[2] = -faceNormal[2];
992  }
993 }
994 
995 #if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_SEGMENTATION) && defined(VISP_HAVE_PCL_FILTERS) && defined(VISP_HAVE_PCL_COMMON)
996 void vpMbtFaceDepthNormal::computeNormalVisibility(float nx, float ny, float nz, const pcl::PointXYZ &centroid_point,
997  pcl::PointXYZ &face_normal)
998 {
999  vpColVector faceNormal(3);
1000  faceNormal[0] = nx;
1001  faceNormal[1] = ny;
1002  faceNormal[2] = nz;
1003  faceNormal.normalize();
1004 
1005  vpColVector e4(3);
1006  e4[0] = -centroid_point.x;
1007  e4[1] = -centroid_point.y;
1008  e4[2] = -centroid_point.z;
1009  e4.normalize();
1010 
1011  double angle = acos(vpColVector::dotProd(e4, faceNormal));
1012  if (angle < M_PI_2) {
1013  face_normal = pcl::PointXYZ(faceNormal[0], faceNormal[1], faceNormal[2]);
1014  }
1015  else {
1016  face_normal = pcl::PointXYZ(-faceNormal[0], -faceNormal[1], -faceNormal[2]);
1017  }
1018 }
1019 #endif
1020 
1021 void vpMbtFaceDepthNormal::computeNormalVisibility(double nx, double ny, double nz, const vpColVector &centroid_point,
1022  vpColVector &face_normal)
1023 {
1024  face_normal.resize(3, false);
1025  face_normal[0] = nx;
1026  face_normal[1] = ny;
1027  face_normal[2] = nz;
1028  face_normal.normalize();
1029 
1030  vpColVector e4 = -centroid_point;
1031  e4.normalize();
1032 
1033  double angle = acos(vpColVector::dotProd(e4, face_normal));
1034  if (angle >= M_PI_2) {
1035  face_normal[0] = -face_normal[0];
1036  face_normal[1] = -face_normal[1];
1037  face_normal[2] = -face_normal[2];
1038  }
1039 }
1040 
1046 {
1049  const vpTranslationVector t = cMo.getTranslationVector();
1050  // const double D = -(t[0] * m_planeCamera.getA() + t[1] * m_planeCamera.getB() + t[2] * m_planeCamera.getC());
1051  const double D = m_planeCamera.getD();
1052  vpPoint centroid;
1053  std::vector<vpPoint> polyPts;
1054  m_polygon->getPolygonClipped(polyPts);
1055  computePolygonCentroid(polyPts, centroid);
1056  centroid.changeFrame(cMo);
1057  centroid.project();
1058  vpColVector c(3);
1059  c[0] = centroid.get_X();
1060  c[1] = centroid.get_Y();
1061  c[2] = centroid.get_Z();
1062  const double L = c.frobeniusNorm();
1063  const double minD = L * cos(maxAngle);
1064  return fabs(D) <= minD;
1065 }
1066 
1068 {
1069  L.resize(3, 6, false, false);
1070 
1071  // Transform the plane equation for the current pose
1074 
1075  double ux = m_planeCamera.getA();
1076  double uy = m_planeCamera.getB();
1077  double uz = m_planeCamera.getC();
1078  double D = m_planeCamera.getD();
1079  double D2 = D * D;
1080 
1081  // Features
1082  features.resize(3, false);
1083  features[0] = -ux / D;
1084  features[1] = -uy / D;
1085  features[2] = -uz / D;
1086 
1087  // L_A
1088  L[0][0] = ux * ux / D2;
1089  L[0][1] = ux * uy / D2;
1090  L[0][2] = ux * uz / D2;
1091  L[0][3] = 0.0;
1092  L[0][4] = uz / D;
1093  L[0][5] = -uy / D;
1094 
1095  // L_B
1096  L[1][0] = ux * uy / D2;
1097  L[1][1] = uy * uy / D2;
1098  L[1][2] = uy * uz / D2;
1099  L[1][3] = -uz / D;
1100  L[1][4] = 0.0;
1101  L[1][5] = ux / D;
1102 
1103  // L_C
1104  L[2][0] = ux * uz / D2;
1105  L[2][1] = uy * uz / D2;
1106  L[2][2] = uz * uz / D2;
1107  L[2][3] = uy / D;
1108  L[2][4] = -ux / D;
1109  L[2][5] = 0.0;
1110 }
1111 
1113  const vpCameraParameters &cam, const vpColor &col, unsigned int thickness,
1114  bool displayFullModel)
1115 {
1116  std::vector<std::vector<double> > models =
1117  getModelForDisplay(I.getWidth(), I.getHeight(), cMo, cam, displayFullModel);
1118 
1119  for (size_t i = 0; i < models.size(); i++) {
1120  vpImagePoint ip1(models[i][1], models[i][2]);
1121  vpImagePoint ip2(models[i][3], models[i][4]);
1122  vpDisplay::displayLine(I, ip1, ip2, col, thickness);
1123  }
1124 }
1125 
1127  const vpCameraParameters &cam, const vpColor &col, unsigned int thickness,
1128  bool displayFullModel)
1129 {
1130  std::vector<std::vector<double> > models =
1131  getModelForDisplay(I.getWidth(), I.getHeight(), cMo, cam, displayFullModel);
1132 
1133  for (size_t i = 0; i < models.size(); i++) {
1134  vpImagePoint ip1(models[i][1], models[i][2]);
1135  vpImagePoint ip2(models[i][3], models[i][4]);
1136  vpDisplay::displayLine(I, ip1, ip2, col, thickness);
1137  }
1138 }
1139 
1141  const vpCameraParameters &cam, double scale, unsigned int thickness)
1142 {
1144  // Desired feature
1145  vpPoint pt_centroid = m_faceDesiredCentroid;
1146  pt_centroid.changeFrame(cMo);
1147  pt_centroid.project();
1148 
1149  vpImagePoint im_centroid;
1150  vpMeterPixelConversion::convertPoint(cam, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
1151 
1152  vpPoint pt_normal = m_faceDesiredNormal;
1153  pt_normal.changeFrame(cMo);
1154  pt_normal.project();
1155 
1156  vpPoint pt_extremity;
1157  pt_extremity.set_X(pt_centroid.get_X() + pt_normal.get_X() * scale);
1158  pt_extremity.set_Y(pt_centroid.get_Y() + pt_normal.get_Y() * scale);
1159  pt_extremity.set_Z(pt_centroid.get_Z() + pt_normal.get_Z() * scale);
1160  pt_extremity.project();
1161 
1162  vpImagePoint im_extremity;
1163  vpMeterPixelConversion::convertPoint(cam, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1164 
1165  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::blue, 4, 2, thickness);
1166 
1167  // Current feature
1168  // Transform the plane equation for the current pose
1171 
1172  double ux = m_planeCamera.getA();
1173  double uy = m_planeCamera.getB();
1174  double uz = m_planeCamera.getC();
1175 
1176  vpColVector correct_normal;
1177  vpCameraParameters cam_copy = cam;
1178  cam_copy.computeFov(I.getWidth(), I.getHeight());
1179  computeNormalVisibility(ux, uy, uz, cMo, cam_copy, correct_normal, pt_centroid);
1180 
1181  pt_centroid.project();
1182  vpMeterPixelConversion::convertPoint(cam_copy, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
1183 
1184  pt_extremity.set_X(pt_centroid.get_X() + correct_normal[0] * scale);
1185  pt_extremity.set_Y(pt_centroid.get_Y() + correct_normal[1] * scale);
1186  pt_extremity.set_Z(pt_centroid.get_Z() + correct_normal[2] * scale);
1187  pt_extremity.project();
1188 
1189  vpMeterPixelConversion::convertPoint(cam_copy, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1190 
1191  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::red, 4, 2, thickness);
1192  }
1193 }
1194 
1196  const vpCameraParameters &cam, double scale, unsigned int thickness)
1197 {
1199  // Desired feature
1200  vpPoint pt_centroid = m_faceDesiredCentroid;
1201  pt_centroid.changeFrame(cMo);
1202  pt_centroid.project();
1203 
1204  vpImagePoint im_centroid;
1205  vpMeterPixelConversion::convertPoint(cam, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
1206 
1207  vpPoint pt_normal = m_faceDesiredNormal;
1208  pt_normal.changeFrame(cMo);
1209  pt_normal.project();
1210 
1211  vpPoint pt_extremity;
1212  pt_extremity.set_X(pt_centroid.get_X() + pt_normal.get_X() * scale);
1213  pt_extremity.set_Y(pt_centroid.get_Y() + pt_normal.get_Y() * scale);
1214  pt_extremity.set_Z(pt_centroid.get_Z() + pt_normal.get_Z() * scale);
1215  pt_extremity.project();
1216 
1217  vpImagePoint im_extremity;
1218  vpMeterPixelConversion::convertPoint(cam, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1219 
1220  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::blue, 4, 2, thickness);
1221 
1222  // Current feature
1223  // Transform the plane equation for the current pose
1226 
1227  double ux = m_planeCamera.getA();
1228  double uy = m_planeCamera.getB();
1229  double uz = m_planeCamera.getC();
1230 
1231  vpColVector correct_normal;
1232  vpCameraParameters cam_copy = cam;
1233  cam_copy.computeFov(I.getWidth(), I.getHeight());
1234  computeNormalVisibility(ux, uy, uz, cMo, cam_copy, correct_normal, pt_centroid);
1235 
1236  pt_centroid.project();
1237  vpMeterPixelConversion::convertPoint(cam_copy, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
1238 
1239  pt_extremity.set_X(pt_centroid.get_X() + correct_normal[0] * scale);
1240  pt_extremity.set_Y(pt_centroid.get_Y() + correct_normal[1] * scale);
1241  pt_extremity.set_Z(pt_centroid.get_Z() + correct_normal[2] * scale);
1242  pt_extremity.project();
1243 
1244  vpMeterPixelConversion::convertPoint(cam_copy, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1245 
1246  vpDisplay::displayArrow(I, im_centroid, im_extremity, vpColor::red, 4, 2, thickness);
1247  }
1248 }
1249 
1250 void vpMbtFaceDepthNormal::estimateFeatures(const std::vector<double> &point_cloud_face, const vpHomogeneousMatrix &cMo,
1251  vpColVector &x_estimated, std::vector<double> &w)
1252 {
1253  vpMbtTukeyEstimator<double> tukey_robust;
1254  std::vector<double> residues(point_cloud_face.size() / 3);
1255 
1256  w.resize(point_cloud_face.size() / 3, 1.0);
1257 
1258  unsigned int max_iter = 30, iter = 0;
1259  double error = 0.0, prev_error = -1.0;
1260  double A = 0.0, B = 0.0, C = 0.0;
1261 
1262  Mat33<double> ATA_3x3;
1263 
1264  bool checkSSE2 = vpCPUFeatures::checkSSE2();
1265 #if !USE_SSE
1266  checkSSE2 = false;
1267 #endif
1268 
1269  if (checkSSE2) {
1270 #if USE_SSE
1271  while (std::fabs(error - prev_error) > 1e-6 && (iter < max_iter)) {
1272  if (iter == 0) {
1273  // Transform the plane equation for the current pose
1276 
1277  double ux = m_planeCamera.getA();
1278  double uy = m_planeCamera.getB();
1279  double uz = m_planeCamera.getC();
1280  double D = m_planeCamera.getD();
1281 
1282  // Features
1283  A = -ux / D;
1284  B = -uy / D;
1285  C = -uz / D;
1286 
1287  size_t cpt = 0;
1288  if (point_cloud_face.size() / 3 >= 2) {
1289  const double *ptr_point_cloud = &point_cloud_face[0];
1290  const __m128d vA = _mm_set1_pd(A);
1291  const __m128d vB = _mm_set1_pd(B);
1292  const __m128d vC = _mm_set1_pd(C);
1293  const __m128d vones = _mm_set1_pd(1.0);
1294 
1295  double *ptr_residues = &residues[0];
1296 
1297  for (; cpt <= point_cloud_face.size() - 6; cpt += 6, ptr_point_cloud += 6, ptr_residues += 2) {
1298  const __m128d vxi = _mm_loadu_pd(ptr_point_cloud);
1299  const __m128d vyi = _mm_loadu_pd(ptr_point_cloud + 2);
1300  const __m128d vZi = _mm_loadu_pd(ptr_point_cloud + 4);
1301  const __m128d vinvZi = _mm_div_pd(vones, vZi);
1302 
1303  const __m128d tmp =
1304  _mm_add_pd(_mm_add_pd(_mm_mul_pd(vA, vxi), _mm_mul_pd(vB, vyi)), _mm_sub_pd(vC, vinvZi));
1305  _mm_storeu_pd(ptr_residues, tmp);
1306  }
1307  }
1308 
1309  for (; cpt < point_cloud_face.size(); cpt += 3) {
1310  double xi = point_cloud_face[cpt];
1311  double yi = point_cloud_face[cpt + 1];
1312  double Zi = point_cloud_face[cpt + 2];
1313 
1314  residues[cpt / 3] = (A * xi + B * yi + C - 1 / Zi);
1315  }
1316  }
1317 
1318  tukey_robust.MEstimator(residues, w, 1e-2);
1319 
1320  __m128d vsum_wi2_xi2 = _mm_setzero_pd();
1321  __m128d vsum_wi2_yi2 = _mm_setzero_pd();
1322  __m128d vsum_wi2 = _mm_setzero_pd();
1323  __m128d vsum_wi2_xi_yi = _mm_setzero_pd();
1324  __m128d vsum_wi2_xi = _mm_setzero_pd();
1325  __m128d vsum_wi2_yi = _mm_setzero_pd();
1326 
1327  __m128d vsum_wi2_xi_Zi = _mm_setzero_pd();
1328  __m128d vsum_wi2_yi_Zi = _mm_setzero_pd();
1329  __m128d vsum_wi2_Zi = _mm_setzero_pd();
1330 
1331  // Estimate A, B, C
1332  size_t cpt = 0;
1333  if (point_cloud_face.size() / 3 >= 2) {
1334  const double *ptr_point_cloud = &point_cloud_face[0];
1335  double *ptr_w = &w[0];
1336 
1337  const __m128d vones = _mm_set1_pd(1.0);
1338 
1339  for (; cpt <= point_cloud_face.size() - 6; cpt += 6, ptr_point_cloud += 6, ptr_w += 2) {
1340  const __m128d vwi2 = _mm_mul_pd(_mm_loadu_pd(ptr_w), _mm_loadu_pd(ptr_w));
1341 
1342  const __m128d vxi = _mm_loadu_pd(ptr_point_cloud);
1343  const __m128d vyi = _mm_loadu_pd(ptr_point_cloud + 2);
1344  const __m128d vZi = _mm_loadu_pd(ptr_point_cloud + 4);
1345  const __m128d vinvZi = _mm_div_pd(vones, vZi);
1346 
1347  vsum_wi2_xi2 = _mm_add_pd(vsum_wi2_xi2, _mm_mul_pd(vwi2, _mm_mul_pd(vxi, vxi)));
1348  vsum_wi2_yi2 = _mm_add_pd(vsum_wi2_yi2, _mm_mul_pd(vwi2, _mm_mul_pd(vyi, vyi)));
1349  vsum_wi2 = _mm_add_pd(vsum_wi2, vwi2);
1350  vsum_wi2_xi_yi = _mm_add_pd(vsum_wi2_xi_yi, _mm_mul_pd(vwi2, _mm_mul_pd(vxi, vyi)));
1351  vsum_wi2_xi = _mm_add_pd(vsum_wi2_xi, _mm_mul_pd(vwi2, vxi));
1352  vsum_wi2_yi = _mm_add_pd(vsum_wi2_yi, _mm_mul_pd(vwi2, vyi));
1353 
1354  const __m128d vwi2_invZi = _mm_mul_pd(vwi2, vinvZi);
1355  vsum_wi2_xi_Zi = _mm_add_pd(vsum_wi2_xi_Zi, _mm_mul_pd(vxi, vwi2_invZi));
1356  vsum_wi2_yi_Zi = _mm_add_pd(vsum_wi2_yi_Zi, _mm_mul_pd(vyi, vwi2_invZi));
1357  vsum_wi2_Zi = _mm_add_pd(vsum_wi2_Zi, vwi2_invZi);
1358  }
1359  }
1360 
1361  double vtmp[2];
1362  _mm_storeu_pd(vtmp, vsum_wi2_xi2);
1363  double sum_wi2_xi2 = vtmp[0] + vtmp[1];
1364 
1365  _mm_storeu_pd(vtmp, vsum_wi2_yi2);
1366  double sum_wi2_yi2 = vtmp[0] + vtmp[1];
1367 
1368  _mm_storeu_pd(vtmp, vsum_wi2);
1369  double sum_wi2 = vtmp[0] + vtmp[1];
1370 
1371  _mm_storeu_pd(vtmp, vsum_wi2_xi_yi);
1372  double sum_wi2_xi_yi = vtmp[0] + vtmp[1];
1373 
1374  _mm_storeu_pd(vtmp, vsum_wi2_xi);
1375  double sum_wi2_xi = vtmp[0] + vtmp[1];
1376 
1377  _mm_storeu_pd(vtmp, vsum_wi2_yi);
1378  double sum_wi2_yi = vtmp[0] + vtmp[1];
1379 
1380  _mm_storeu_pd(vtmp, vsum_wi2_xi_Zi);
1381  double sum_wi2_xi_Zi = vtmp[0] + vtmp[1];
1382 
1383  _mm_storeu_pd(vtmp, vsum_wi2_yi_Zi);
1384  double sum_wi2_yi_Zi = vtmp[0] + vtmp[1];
1385 
1386  _mm_storeu_pd(vtmp, vsum_wi2_Zi);
1387  double sum_wi2_Zi = vtmp[0] + vtmp[1];
1388 
1389  for (; cpt < point_cloud_face.size(); cpt += 3) {
1390  double wi2 = w[cpt / 3] * w[cpt / 3];
1391 
1392  double xi = point_cloud_face[cpt];
1393  double yi = point_cloud_face[cpt + 1];
1394  double Zi = point_cloud_face[cpt + 2];
1395  double invZi = 1.0 / Zi;
1396 
1397  sum_wi2_xi2 += wi2 * xi * xi;
1398  sum_wi2_yi2 += wi2 * yi * yi;
1399  sum_wi2 += wi2;
1400  sum_wi2_xi_yi += wi2 * xi * yi;
1401  sum_wi2_xi += wi2 * xi;
1402  sum_wi2_yi += wi2 * yi;
1403 
1404  sum_wi2_xi_Zi += wi2 * xi * invZi;
1405  sum_wi2_yi_Zi += wi2 * yi * invZi;
1406  sum_wi2_Zi += wi2 * invZi;
1407  }
1408 
1409  ATA_3x3[0] = sum_wi2_xi2;
1410  ATA_3x3[1] = sum_wi2_xi_yi;
1411  ATA_3x3[2] = sum_wi2_xi;
1412  ATA_3x3[3] = sum_wi2_xi_yi;
1413  ATA_3x3[4] = sum_wi2_yi2;
1414  ATA_3x3[5] = sum_wi2_yi;
1415  ATA_3x3[6] = sum_wi2_xi;
1416  ATA_3x3[7] = sum_wi2_yi;
1417  ATA_3x3[8] = sum_wi2;
1418 
1419  Mat33<double> minv = ATA_3x3.inverse();
1420 
1421  A = minv[0] * sum_wi2_xi_Zi + minv[1] * sum_wi2_yi_Zi + minv[2] * sum_wi2_Zi;
1422  B = minv[3] * sum_wi2_xi_Zi + minv[4] * sum_wi2_yi_Zi + minv[5] * sum_wi2_Zi;
1423  C = minv[6] * sum_wi2_xi_Zi + minv[7] * sum_wi2_yi_Zi + minv[8] * sum_wi2_Zi;
1424 
1425  cpt = 0;
1426 
1427  // Compute error
1428  prev_error = error;
1429  error = 0.0;
1430 
1431  __m128d verror = _mm_set1_pd(0.0);
1432  if (point_cloud_face.size() / 3 >= 2) {
1433  const double *ptr_point_cloud = &point_cloud_face[0];
1434  const __m128d vA = _mm_set1_pd(A);
1435  const __m128d vB = _mm_set1_pd(B);
1436  const __m128d vC = _mm_set1_pd(C);
1437  const __m128d vones = _mm_set1_pd(1.0);
1438 
1439  double *ptr_residues = &residues[0];
1440 
1441  for (; cpt <= point_cloud_face.size() - 6; cpt += 6, ptr_point_cloud += 6, ptr_residues += 2) {
1442  const __m128d vxi = _mm_loadu_pd(ptr_point_cloud);
1443  const __m128d vyi = _mm_loadu_pd(ptr_point_cloud + 2);
1444  const __m128d vZi = _mm_loadu_pd(ptr_point_cloud + 4);
1445  const __m128d vinvZi = _mm_div_pd(vones, vZi);
1446 
1447  const __m128d tmp = _mm_add_pd(_mm_add_pd(_mm_mul_pd(vA, vxi), _mm_mul_pd(vB, vyi)), _mm_sub_pd(vC, vinvZi));
1448  verror = _mm_add_pd(verror, _mm_mul_pd(tmp, tmp));
1449 
1450  _mm_storeu_pd(ptr_residues, tmp);
1451  }
1452  }
1453 
1454  _mm_storeu_pd(vtmp, verror);
1455  error = vtmp[0] + vtmp[1];
1456 
1457  for (size_t idx = cpt; idx < point_cloud_face.size(); idx += 3) {
1458  double xi = point_cloud_face[idx];
1459  double yi = point_cloud_face[idx + 1];
1460  double Zi = point_cloud_face[idx + 2];
1461 
1462  error += vpMath::sqr(A * xi + B * yi + C - 1 / Zi);
1463  residues[idx / 3] = (A * xi + B * yi + C - 1 / Zi);
1464  }
1465 
1466  error /= point_cloud_face.size() / 3;
1467 
1468  iter++;
1469  } // while ( std::fabs(error - prev_error) > 1e-6 && (iter < max_iter) )
1470 #endif
1471  }
1472  else {
1473  while (std::fabs(error - prev_error) > 1e-6 && (iter < max_iter)) {
1474  if (iter == 0) {
1475  // Transform the plane equation for the current pose
1478 
1479  double ux = m_planeCamera.getA();
1480  double uy = m_planeCamera.getB();
1481  double uz = m_planeCamera.getC();
1482  double D = m_planeCamera.getD();
1483 
1484  // Features
1485  A = -ux / D;
1486  B = -uy / D;
1487  C = -uz / D;
1488 
1489  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1490  double xi = point_cloud_face[3 * i];
1491  double yi = point_cloud_face[3 * i + 1];
1492  double Zi = point_cloud_face[3 * i + 2];
1493 
1494  residues[i] = (A * xi + B * yi + C - 1 / Zi);
1495  }
1496  }
1497 
1498  tukey_robust.MEstimator(residues, w, 1e-2);
1499 
1500  // Estimate A, B, C
1501  double sum_wi2_xi2 = 0.0, sum_wi2_yi2 = 0.0, sum_wi2 = 0.0;
1502  double sum_wi2_xi_yi = 0.0, sum_wi2_xi = 0.0, sum_wi2_yi = 0.0;
1503 
1504  double sum_wi2_xi_Zi = 0.0, sum_wi2_yi_Zi = 0.0, sum_wi2_Zi = 0.0;
1505 
1506  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1507  double wi2 = w[i] * w[i];
1508 
1509  double xi = point_cloud_face[3 * i];
1510  double yi = point_cloud_face[3 * i + 1];
1511  double Zi = point_cloud_face[3 * i + 2];
1512  double invZi = 1 / Zi;
1513 
1514  sum_wi2_xi2 += wi2 * xi * xi;
1515  sum_wi2_yi2 += wi2 * yi * yi;
1516  sum_wi2 += wi2;
1517  sum_wi2_xi_yi += wi2 * xi * yi;
1518  sum_wi2_xi += wi2 * xi;
1519  sum_wi2_yi += wi2 * yi;
1520 
1521  sum_wi2_xi_Zi += wi2 * xi * invZi;
1522  sum_wi2_yi_Zi += wi2 * yi * invZi;
1523  sum_wi2_Zi += wi2 * invZi;
1524  }
1525 
1526  ATA_3x3[0] = sum_wi2_xi2;
1527  ATA_3x3[1] = sum_wi2_xi_yi;
1528  ATA_3x3[2] = sum_wi2_xi;
1529  ATA_3x3[3] = sum_wi2_xi_yi;
1530  ATA_3x3[4] = sum_wi2_yi2;
1531  ATA_3x3[5] = sum_wi2_yi;
1532  ATA_3x3[6] = sum_wi2_xi;
1533  ATA_3x3[7] = sum_wi2_yi;
1534  ATA_3x3[8] = sum_wi2;
1535 
1536  Mat33<double> minv = ATA_3x3.inverse();
1537 
1538  A = minv[0] * sum_wi2_xi_Zi + minv[1] * sum_wi2_yi_Zi + minv[2] * sum_wi2_Zi;
1539  B = minv[3] * sum_wi2_xi_Zi + minv[4] * sum_wi2_yi_Zi + minv[5] * sum_wi2_Zi;
1540  C = minv[6] * sum_wi2_xi_Zi + minv[7] * sum_wi2_yi_Zi + minv[8] * sum_wi2_Zi;
1541 
1542  prev_error = error;
1543  error = 0.0;
1544 
1545  // Compute error
1546  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1547  double xi = point_cloud_face[3 * i];
1548  double yi = point_cloud_face[3 * i + 1];
1549  double Zi = point_cloud_face[3 * i + 2];
1550 
1551  error += vpMath::sqr(A * xi + B * yi + C - 1 / Zi);
1552  residues[i] = (A * xi + B * yi + C - 1 / Zi);
1553  }
1554 
1555  error /= point_cloud_face.size() / 3;
1556 
1557  iter++;
1558  } // while ( std::fabs(error - prev_error) > 1e-6 && (iter < max_iter) )
1559  }
1560 
1561  x_estimated.resize(3, false);
1562  x_estimated[0] = A;
1563  x_estimated[1] = B;
1564  x_estimated[2] = C;
1565 }
1566 
1567 void vpMbtFaceDepthNormal::estimatePlaneEquationSVD(const std::vector<double> &point_cloud_face,
1568  const vpHomogeneousMatrix &cMo,
1569  vpColVector &plane_equation_estimated, vpColVector &centroid)
1570 {
1571  unsigned int max_iter = 10;
1572  double prev_error = 1e3;
1573  double error = 1e3 - 1;
1574 
1575  std::vector<double> weights(point_cloud_face.size() / 3, 1.0);
1576  std::vector<double> residues(point_cloud_face.size() / 3);
1577  vpMatrix M((unsigned int)(point_cloud_face.size() / 3), 3);
1578  vpMbtTukeyEstimator<double> tukey;
1579  vpColVector normal;
1580 
1581  for (unsigned int iter = 0; iter < max_iter && std::fabs(error - prev_error) > 1e-6; iter++) {
1582  if (iter != 0) {
1583  tukey.MEstimator(residues, weights, 1e-4);
1584  }
1585  else {
1586  // Transform the plane equation for the current pose
1589 
1590  double A = m_planeCamera.getA();
1591  double B = m_planeCamera.getB();
1592  double C = m_planeCamera.getC();
1593  double D = m_planeCamera.getD();
1594 
1595  // Compute distance point to estimated plane
1596  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1597  residues[i] = std::fabs(A * point_cloud_face[3 * i] + B * point_cloud_face[3 * i + 1] +
1598  C * point_cloud_face[3 * i + 2] + D) /
1599  sqrt(A * A + B * B + C * C);
1600  }
1601 
1602  tukey.MEstimator(residues, weights, 1e-4);
1603  plane_equation_estimated.resize(4, false);
1604  }
1605 
1606  // Compute centroid
1607  double centroid_x = 0.0, centroid_y = 0.0, centroid_z = 0.0;
1608  double total_w = 0.0;
1609 
1610  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1611  centroid_x += weights[i] * point_cloud_face[3 * i];
1612  centroid_y += weights[i] * point_cloud_face[3 * i + 1];
1613  centroid_z += weights[i] * point_cloud_face[3 * i + 2];
1614  total_w += weights[i];
1615  }
1616 
1617  centroid_x /= total_w;
1618  centroid_y /= total_w;
1619  centroid_z /= total_w;
1620 
1621  // Minimization
1622  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1623  M[(unsigned int)i][0] = weights[i] * (point_cloud_face[3 * i] - centroid_x);
1624  M[(unsigned int)i][1] = weights[i] * (point_cloud_face[3 * i + 1] - centroid_y);
1625  M[(unsigned int)i][2] = weights[i] * (point_cloud_face[3 * i + 2] - centroid_z);
1626  }
1627 
1628  vpMatrix J = M.t() * M;
1629 
1630  vpColVector W;
1631  vpMatrix V;
1632  J.svd(W, V);
1633 
1634  double smallestSv = W[0];
1635  unsigned int indexSmallestSv = 0;
1636  for (unsigned int i = 1; i < W.size(); i++) {
1637  if (W[i] < smallestSv) {
1638  smallestSv = W[i];
1639  indexSmallestSv = i;
1640  }
1641  }
1642 
1643  normal = V.getCol(indexSmallestSv);
1644 
1645  // Compute plane equation
1646  double A = normal[0], B = normal[1], C = normal[2];
1647  double D = -(A * centroid_x + B * centroid_y + C * centroid_z);
1648 
1649  // Update plane equation
1650  plane_equation_estimated[0] = A;
1651  plane_equation_estimated[1] = B;
1652  plane_equation_estimated[2] = C;
1653  plane_equation_estimated[3] = D;
1654 
1655  // Compute error points to estimated plane
1656  prev_error = error;
1657  error = 0.0;
1658  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1659  residues[i] = std::fabs(A * point_cloud_face[3 * i] + B * point_cloud_face[3 * i + 1] +
1660  C * point_cloud_face[3 * i + 2] + D) /
1661  sqrt(A * A + B * B + C * C);
1662  error += weights[i] * residues[i];
1663  }
1664  error /= total_w;
1665  }
1666 
1667  // Update final weights
1668  tukey.MEstimator(residues, weights, 1e-4);
1669 
1670  // Update final centroid
1671  centroid.resize(3, false);
1672  double total_w = 0.0;
1673 
1674  for (size_t i = 0; i < point_cloud_face.size() / 3; i++) {
1675  centroid[0] += weights[i] * point_cloud_face[3 * i];
1676  centroid[1] += weights[i] * point_cloud_face[3 * i + 1];
1677  centroid[2] += weights[i] * point_cloud_face[3 * i + 2];
1678  total_w += weights[i];
1679  }
1680 
1681  centroid[0] /= total_w;
1682  centroid[1] /= total_w;
1683  centroid[2] /= total_w;
1684 
1685  // Compute final plane equation
1686  double A = normal[0], B = normal[1], C = normal[2];
1687  double D = -(A * centroid[0] + B * centroid[1] + C * centroid[2]);
1688 
1689  // Update final plane equation
1690  plane_equation_estimated[0] = A;
1691  plane_equation_estimated[1] = B;
1692  plane_equation_estimated[2] = C;
1693  plane_equation_estimated[3] = D;
1694 }
1695 
1701 std::vector<std::vector<double> >
1703 {
1704  std::vector<std::vector<double> > features;
1705 
1707  // Desired feature
1708  vpPoint pt_centroid = m_faceDesiredCentroid;
1709  pt_centroid.changeFrame(cMo);
1710  pt_centroid.project();
1711 
1712  vpImagePoint im_centroid;
1713  vpMeterPixelConversion::convertPoint(cam, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
1714 
1715  vpPoint pt_normal = m_faceDesiredNormal;
1716  pt_normal.changeFrame(cMo);
1717  pt_normal.project();
1718 
1719  vpPoint pt_extremity;
1720  pt_extremity.set_X(pt_centroid.get_X() + pt_normal.get_X() * scale);
1721  pt_extremity.set_Y(pt_centroid.get_Y() + pt_normal.get_Y() * scale);
1722  pt_extremity.set_Z(pt_centroid.get_Z() + pt_normal.get_Z() * scale);
1723  pt_extremity.project();
1724 
1725  vpImagePoint im_extremity;
1726  vpMeterPixelConversion::convertPoint(cam, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1727 
1728  {
1729 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
1730  std::vector<double> params = { 2, //desired normal
1731  im_centroid.get_i(),
1732  im_centroid.get_j(),
1733  im_extremity.get_i(),
1734  im_extremity.get_j() };
1735 #else
1736  std::vector<double> params;
1737  params.push_back(2); //desired normal
1738  params.push_back(im_centroid.get_i());
1739  params.push_back(im_centroid.get_j());
1740  params.push_back(im_extremity.get_i());
1741  params.push_back(im_extremity.get_j());
1742 #endif
1743  features.push_back(params);
1744  }
1745 
1746  // Current feature
1747  // Transform the plane equation for the current pose
1750 
1751  double ux = m_planeCamera.getA();
1752  double uy = m_planeCamera.getB();
1753  double uz = m_planeCamera.getC();
1754 
1755  vpColVector correct_normal;
1756  computeNormalVisibility(ux, uy, uz, cMo, cam, correct_normal, pt_centroid);
1757 
1758  pt_centroid.project();
1759  vpMeterPixelConversion::convertPoint(cam, pt_centroid.get_x(), pt_centroid.get_y(), im_centroid);
1760 
1761  pt_extremity.set_X(pt_centroid.get_X() + correct_normal[0] * scale);
1762  pt_extremity.set_Y(pt_centroid.get_Y() + correct_normal[1] * scale);
1763  pt_extremity.set_Z(pt_centroid.get_Z() + correct_normal[2] * scale);
1764  pt_extremity.project();
1765 
1766  vpMeterPixelConversion::convertPoint(cam, pt_extremity.get_x(), pt_extremity.get_y(), im_extremity);
1767 
1768  {
1769 #if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
1770  std::vector<double> params = { 3, //normal at current pose
1771  im_centroid.get_i(),
1772  im_centroid.get_j(),
1773  im_extremity.get_i(),
1774  im_extremity.get_j() };
1775 #else
1776  std::vector<double> params;
1777  params.push_back(3); //normal at current pose
1778  params.push_back(im_centroid.get_i());
1779  params.push_back(im_centroid.get_j());
1780  params.push_back(im_extremity.get_i());
1781  params.push_back(im_extremity.get_j());
1782 #endif
1783  features.push_back(params);
1784  }
1785  }
1786 
1787  return features;
1788 }
1789 
1801 std::vector<std::vector<double> > vpMbtFaceDepthNormal::getModelForDisplay(unsigned int width, unsigned int height,
1802  const vpHomogeneousMatrix &cMo,
1803  const vpCameraParameters &cam,
1804  bool displayFullModel)
1805 {
1806  std::vector<std::vector<double> > models;
1807 
1808  if ((m_polygon->isVisible() && m_isTrackedDepthNormalFace) || displayFullModel) {
1810 
1811  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
1812  ++it) {
1813  vpMbtDistanceLine *line = *it;
1814  std::vector<std::vector<double> > lineModels =
1815  line->getModelForDisplay(width, height, cMo, cam, displayFullModel);
1816  models.insert(models.end(), lineModels.begin(), lineModels.end());
1817  }
1818  }
1819 
1820  return models;
1821 }
1822 
1832 bool vpMbtFaceDepthNormal::samePoint(const vpPoint &P1, const vpPoint &P2) const
1833 {
1834  double dx = fabs(P1.get_oX() - P2.get_oX());
1835  double dy = fabs(P1.get_oY() - P2.get_oY());
1836  double dz = fabs(P1.get_oZ() - P2.get_oZ());
1837 
1838  if (dx <= std::numeric_limits<double>::epsilon() && dy <= std::numeric_limits<double>::epsilon() &&
1839  dz <= std::numeric_limits<double>::epsilon())
1840  return true;
1841  else
1842  return false;
1843 }
1844 
1846 {
1847  m_cam = camera;
1848 
1849  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
1850  ++it) {
1851  (*it)->setCameraParameters(camera);
1852  }
1853 }
1854 
1856 {
1857  m_useScanLine = v;
1858 
1859  for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_listOfFaceLines.begin(); it != m_listOfFaceLines.end();
1860  ++it) {
1861  (*it)->useScanLine = v;
1862  }
1863 }
1864 END_VISP_NAMESPACE
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:349
Generic class defining intrinsic camera parameters.
void computeFov(const unsigned int &w, const unsigned int &h)
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
static double dotProd(const vpColVector &a, const vpColVector &b)
vpColVector & normalize()
double frobeniusNorm() const
void resize(unsigned int i, bool flagNullify=true)
Definition: vpColVector.h:1143
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:157
static const vpColor red
Definition: vpColor.h:217
static const vpColor blue
Definition: vpColor.h:223
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
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)
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:73
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix inverse() const
vpTranslationVector getTranslationVector() const
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_j() const
Definition: vpImagePoint.h:125
double get_i() const
Definition: vpImagePoint.h:114
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getHeight() const
Definition: vpImage.h:181
static double sqr(double x)
Definition: vpMath.h:203
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
void svd(vpColVector &w, vpMatrix &V)
vpColVector getCol(unsigned int j) const
Definition: vpMatrix.cpp:548
vpMatrix t() const
vpMbScanLine & getMbScanLineRenderer()
bool isVisible(unsigned int i)
void computeScanLineQuery(const vpPoint &a, const vpPoint &b, std::vector< std::pair< vpPoint, vpPoint > > &lines, const bool &displayResults=false)
Manage the line of a polygon used in the model-based tracker.
void setIndex(unsigned int i)
vpPoint * p2
The second extremity.
std::list< int > Lindex_polygon
Index of the faces which contain the line.
void buildFrom(vpPoint &_p1, vpPoint &_p2, vpUniRand &rand_gen)
vpMbHiddenFaces< vpMbtPolygon > * hiddenface
Pointer to the list of faces.
std::vector< std::vector< double > > getModelForDisplay(unsigned int width, unsigned int height, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, bool displayFullModel=false)
bool useScanLine
Use scanline rendering.
vpPoint * p1
The first extremity.
void setCameraParameters(const vpCameraParameters &camera)
void setName(const std::string &line_name)
void setVisible(bool _isvisible)
void addPolygon(const int &index)
vpMbtPolygon & getPolygon()
double m_pclPlaneEstimationRansacThreshold
PCL plane estimation RANSAC threshold.
int m_pclPlaneEstimationMethod
PCL plane estimation method.
double m_distNearClip
Distance for near clipping.
void computeInteractionMatrix(const vpHomogeneousMatrix &cMo, vpMatrix &L, vpColVector &features)
std::vector< std::vector< double > > getModelForDisplay(unsigned int width, unsigned int height, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, bool displayFullModel=false)
void addLine(vpPoint &p1, vpPoint &p2, vpMbHiddenFaces< vpMbtPolygon > *const faces, vpUniRand &rand_gen, int polygon=-1, std::string name="")
void setCameraParameters(const vpCameraParameters &camera)
void computeDesiredFeaturesSVD(const std::vector< double > &point_cloud_face, const vpHomogeneousMatrix &cMo, vpColVector &desired_features, vpColVector &desired_normal, vpColVector &centroid_point)
double m_distFarClip
Distance for near clipping.
bool samePoint(const vpPoint &P1, const vpPoint &P2) const
void displayFeature(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double scale=0.05, unsigned int thickness=1)
vpMbHiddenFaces< vpMbtPolygon > * m_hiddenFace
Pointer to the list of faces.
std::vector< std::vector< double > > getFeaturesForDisplay(const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double scale=0.05)
bool computePolygonCentroid(const std::vector< vpPoint > &points, vpPoint &centroid)
void computeROI(const vpHomogeneousMatrix &cMo, unsigned int width, unsigned int height, std::vector< vpImagePoint > &roiPts)
void estimatePlaneEquationSVD(const std::vector< double > &point_cloud_face, const vpHomogeneousMatrix &cMo, vpColVector &plane_equation_estimated, vpColVector &centroid)
std::vector< vpMbtDistanceLine * > m_listOfFaceLines
void computeDesiredNormalAndCentroid(const vpHomogeneousMatrix &cMo, const vpColVector &desired_normal, const vpColVector &centroid_point)
vpFeatureEstimationType m_featureEstimationMethod
Method to estimate the desired features.
vpMbtPolygon * m_polygon
Polygon defining the face.
vpPoint m_faceDesiredCentroid
Desired centroid (computed from the sensor)
void display(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const vpColor &col, unsigned int thickness=1, bool displayFullModel=false)
vpCameraParameters m_cam
Camera intrinsic parameters.
@ ROBUST_FEATURE_ESTIMATION
Robust scheme to estimate the normal of the plane.
@ ROBUST_SVD_PLANE_ESTIMATION
Use SVD and robust scheme to estimate the normal of the plane.
@ PCL_PLANE_ESTIMATION
Use PCL to estimate the normal of the plane.
vpPlane m_planeObject
Plane equation described in the object frame.
bool m_faceActivated
True if the face should be considered by the tracker.
@ GEOMETRIC_CENTROID
Compute the geometric centroid.
vpFaceCentroidType m_faceCentroidMethod
Method to compute the face centroid for the current features.
bool planeIsInvalid(const vpHomogeneousMatrix &cMo, double maxAngle)
int m_pclPlaneEstimationRansacMaxIter
PCL pane estimation max number of iterations.
unsigned int m_clippingFlag
Flags specifying which clipping to used.
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)
vpPoint m_faceDesiredNormal
Face (normalized) normal (computed from the sensor)
void estimateFeatures(const std::vector< double > &point_cloud_face, const vpHomogeneousMatrix &cMo, vpColVector &x_estimated, std::vector< double > &weights)
std::vector< PolygonLine > m_polygonLines
bool computeDesiredFeaturesPCL(const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &point_cloud_face, vpColVector &desired_features, vpColVector &desired_normal, vpColVector &centroid_point)
void computeNormalVisibility(double nx, double ny, double nz, const vpColVector &centroid_point, vpColVector &face_normal)
bool m_useScanLine
Scan line visibility.
bool computeDesiredFeatures(const vpHomogeneousMatrix &cMo, unsigned int width, unsigned int height, const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &point_cloud, vpColVector &desired_features, unsigned int stepX, unsigned int stepY, const vpImage< bool > *mask=nullptr)
virtual bool isVisible(const vpHomogeneousMatrix &cMo, double alpha, const bool &modulo=false, const vpCameraParameters &cam=vpCameraParameters(), unsigned int width=0, unsigned int height=0)
int getIndex() const
Definition: vpMbtPolygon.h:93
static bool inRoiMask(const vpImage< bool > *mask, unsigned int i, unsigned int j)
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
void changeFrame(const vpHomogeneousMatrix &cMo)
Definition: vpPlane.cpp:391
double getD() const
Definition: vpPlane.h:106
double getA() const
Definition: vpPlane.h:100
double getC() const
Definition: vpPlane.h:104
double getB() const
Definition: vpPlane.h:102
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Definition: vpPoint.h:79
double get_oX() const
Get the point oX coordinate in the object frame.
Definition: vpPoint.cpp:411
double get_y() const
Get the point y coordinate in the image plane.
Definition: vpPoint.cpp:422
double get_Y() const
Get the point cY coordinate in the camera frame.
Definition: vpPoint.cpp:404
double get_oZ() const
Get the point oZ coordinate in the object frame.
Definition: vpPoint.cpp:415
void set_X(double cX)
Set the point cX coordinate in the camera frame.
Definition: vpPoint.cpp:446
double get_x() const
Get the point x coordinate in the image plane.
Definition: vpPoint.cpp:420
void set_Y(double cY)
Set the point cY coordinate in the camera frame.
Definition: vpPoint.cpp:448
double get_Z() const
Get the point cZ coordinate in the camera frame.
Definition: vpPoint.cpp:406
void set_Z(double cZ)
Set the point cZ coordinate in the camera frame.
Definition: vpPoint.cpp:450
double get_oY() const
Get the point oY coordinate in the object frame.
Definition: vpPoint.cpp:413
void changeFrame(const vpHomogeneousMatrix &cMo, vpColVector &cP) const VP_OVERRIDE
Definition: vpPoint.cpp:267
double get_X() const
Get the point cX coordinate in the camera frame.
Definition: vpPoint.cpp:402
void setWorldCoordinates(double oX, double oY, double oZ)
Definition: vpPoint.cpp:111
Implements a 3D polygon with render functionalities like clipping.
Definition: vpPolygon3D.h:57
void setFarClippingDistance(const double &dist)
Definition: vpPolygon3D.h:192
void setNearClippingDistance(const double &dist)
Definition: vpPolygon3D.h:205
void setClipping(const unsigned int &flags)
Definition: vpPolygon3D.h:185
void getRoiClipped(const vpCameraParameters &cam, std::vector< vpImagePoint > &roi)
void getPolygonClipped(std::vector< std::pair< vpPoint, unsigned int > > &poly)
Defines a generic 2D polygon.
Definition: vpPolygon.h:103
vpRect getBoundingBox() const
Definition: vpPolygon.h:164
bool isInside(const vpImagePoint &iP, const PointInPolygonMethod &method=PnPolyRayCasting) const
Definition: vpPolygon.cpp:400
Defines a rectangle in the plane.
Definition: vpRect.h:79
double getWidth() const
Definition: vpRect.h:227
void setTop(double pos)
Definition: vpRect.h:357
double getLeft() const
Definition: vpRect.h:173
void setLeft(double pos)
Definition: vpRect.h:321
void setRight(double pos)
Definition: vpRect.h:348
double getRight() const
Definition: vpRect.h:179
double getBottom() const
Definition: vpRect.h:97
double getHeight() const
Definition: vpRect.h:166
void setBottom(double pos)
Definition: vpRect.h:288
double getTop() const
Definition: vpRect.h:192
Class that consider the case of a translation vector.
Class for generating random numbers with uniform probability density.
Definition: vpUniRand.h:127
VISP_EXPORT bool checkSSE2()