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