Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpMbTracker.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 * Generic model based tracker
32 */
33
38
39#include <algorithm>
40#include <iostream>
41#include <limits>
42#include <sstream>
43
44#include <visp3/core/vpConfig.h>
45#if defined(VISP_HAVE_SIMDLIB)
46#include <Simd/SimdLib.h>
47#endif
48
49#include <visp3/core/vpColVector.h>
50#include <visp3/core/vpDebug.h>
51#include <visp3/core/vpDisplay.h>
52#include <visp3/core/vpMath.h>
53#include <visp3/core/vpMatrix.h>
54#include <visp3/core/vpPoint.h>
55#include <visp3/vision/vpPose.h>
56#ifdef VISP_HAVE_MODULE_GUI
57#include <visp3/gui/vpDisplayFactory.h>
58#endif
59#include <visp3/core/vpCameraParameters.h>
60#include <visp3/core/vpColor.h>
61#include <visp3/core/vpException.h>
62#include <visp3/core/vpIoTools.h>
63#include <visp3/core/vpPixelMeterConversion.h>
64#ifdef VISP_HAVE_MODULE_IO
65#include <visp3/io/vpImageIo.h>
66#endif
67#include <visp3/core/vpCPUFeatures.h>
68#include <visp3/core/vpIoTools.h>
69#include <visp3/core/vpMatrixException.h>
70#include <visp3/core/vpTrackingException.h>
71#include <visp3/mbt/vpMbTracker.h>
72
73#include <visp3/core/vpImageFilter.h>
74#include <visp3/mbt/vpMbtXmlGenericParser.h>
75
76#ifdef VISP_HAVE_COIN3D
77// Inventor includes
78#include <Inventor/VRMLnodes/SoVRMLCoordinate.h>
79#include <Inventor/VRMLnodes/SoVRMLGroup.h>
80#include <Inventor/VRMLnodes/SoVRMLIndexedFaceSet.h>
81#include <Inventor/VRMLnodes/SoVRMLIndexedLineSet.h>
82#include <Inventor/VRMLnodes/SoVRMLShape.h>
83#include <Inventor/VRMLnodes/SoVRMLTransform.h>
84#include <Inventor/actions/SoGetMatrixAction.h>
85#include <Inventor/actions/SoGetPrimitiveCountAction.h>
86#include <Inventor/actions/SoSearchAction.h>
87#include <Inventor/actions/SoToVRML2Action.h>
88#include <Inventor/actions/SoWriteAction.h>
89#include <Inventor/misc/SoChildList.h>
90#include <Inventor/nodes/SoSeparator.h>
91#endif
92
93#if defined(VISP_HAVE_THREADS)
94#include <mutex>
95#endif
96
98#ifndef DOXYGEN_SHOULD_SKIP_THIS
99namespace
100{
101#if defined(VISP_HAVE_THREADS)
102std::mutex g_mutex_cout;
103#endif
107struct SegmentInfo
108{
109 SegmentInfo() : extremities(), name(), useLod(false), minLineLengthThresh(0.) { }
110
111 std::vector<vpPoint> extremities;
112 std::string name;
113 bool useLod;
114 double minLineLengthThresh;
115};
116
121struct PolygonFaceInfo
122{
123 PolygonFaceInfo(double dist, const vpPolygon &poly, const std::vector<vpPoint> &corners)
124 : distanceToCamera(dist), polygon(poly), faceCorners(corners)
125 { }
126
127 bool operator<(const PolygonFaceInfo &pfi) const { return distanceToCamera < pfi.distanceToCamera; }
128
129 double distanceToCamera;
130 vpPolygon polygon;
131 std::vector<vpPoint> faceCorners;
132};
133
141std::istream &safeGetline(std::istream &is, std::string &t)
142{
143 t.clear();
144
145 // The characters in the stream are read one-by-one using a std::streambuf.
146 // That is faster than reading them one-by-one using the std::istream.
147 // Code that uses streambuf this way must be guarded by a sentry object.
148 // The sentry object performs various tasks,
149 // such as thread synchronization and updating the stream state.
150
151 std::istream::sentry se(is, true);
152 std::streambuf *sb = is.rdbuf();
153
154 for (;;) {
155 int c = sb->sbumpc();
156 if (c == '\n') {
157 return is;
158 }
159 else if (c == '\r') {
160 if (sb->sgetc() == '\n')
161 sb->sbumpc();
162 return is;
163 }
164 else if (c == std::streambuf::traits_type::eof()) {
165 // Also handle the case when the last line has no line ending
166 if (t.empty())
167 is.setstate(std::ios::eofbit);
168 return is;
169 }
170 else { // default case
171 t += static_cast<char>(c);
172 }
173 }
174}
175} // namespace
176#endif // DOXYGEN_SHOULD_SKIP_THIS
177
187 angleDisappears(vpMath::rad(89)), distNearClip(0.001), distFarClip(100), clippingFlag(vpPolygon3D::NO_CLIPPING),
188 useOgre(false), ogreShowConfigDialog(false), useScanLine(false), nbPoints(0), nbLines(0), nbPolygonLines(0),
196 m_rand()
197{
198 oJo.eye();
199 // Map used to parse additional information in CAO model files,
200 // like name of faces or LOD setting
201 mapOfParameterNames["name"] = "string";
202 mapOfParameterNames["minPolygonAreaThreshold"] = "number";
203 mapOfParameterNames["minLineLengthThreshold"] = "number";
204 mapOfParameterNames["useLod"] = "boolean";
205
208}
209
215{
216 *this = tracker;
217}
218
224{
225 m_cam = tracker.m_cam;
226 m_cMo = tracker.m_cMo;
227 oJo = tracker.oJo;
228 m_isoJoIdentity = tracker.m_isoJoIdentity;
229 modelFileName = tracker.modelFileName;
230 modelInitialised = tracker.modelInitialised;
231 poseSavingFilename = tracker.poseSavingFilename;
232 computeCovariance = tracker.computeCovariance;
233 covarianceMatrix = tracker.covarianceMatrix;
234 computeProjError = tracker.computeProjError;
235 projectionError = tracker.projectionError;
236 displayFeatures = tracker.displayFeatures;
237 m_optimizationMethod = tracker.m_optimizationMethod;
238 faces = tracker.faces;
239 angleAppears = tracker.angleAppears;
240 angleDisappears = tracker.angleDisappears;
241 distNearClip = tracker.distNearClip;
242 distFarClip = tracker.distFarClip;
243 clippingFlag = tracker.clippingFlag;
244 useOgre = tracker.useOgre;
245 ogreShowConfigDialog = tracker.ogreShowConfigDialog;
246 useScanLine = tracker.useScanLine;
247 m_nbInitPoints = tracker.m_nbInitPoints;
248 m_maxInitPoints = tracker.m_maxInitPoints;
249 nbPoints = tracker.nbPoints;
250 nbLines = tracker.nbLines;
251 nbPolygonLines = tracker.nbPolygonLines;
252 nbPolygonPoints = tracker.nbPolygonPoints;
253 nbCylinders = tracker.nbCylinders;
254 nbCircles = tracker.nbCircles;
255 useLodGeneral = tracker.useLodGeneral;
256 applyLodSettingInConfig = tracker.applyLodSettingInConfig;
257 minLineLengthThresholdGeneral = tracker.minLineLengthThresholdGeneral;
258 minPolygonAreaThresholdGeneral = tracker.minPolygonAreaThresholdGeneral;
259 mapOfParameterNames = tracker.mapOfParameterNames;
260 m_computeInteraction = tracker.m_computeInteraction;
261 m_lambda = tracker.m_lambda;
262 m_maxIter = tracker.m_maxIter;
263 m_stopCriteriaEpsilon = tracker.m_stopCriteriaEpsilon;
264 m_initialMu = tracker.m_initialMu;
265 m_projectionErrorLines = tracker.m_projectionErrorLines;
266 m_projectionErrorCylinders = tracker.m_projectionErrorCylinders;
267 m_projectionErrorCircles = tracker.m_projectionErrorCircles;
268 m_projectionErrorFaces = tracker.m_projectionErrorFaces;
269 m_projectionErrorOgreShowConfigDialog = tracker.m_projectionErrorOgreShowConfigDialog;
270 m_projectionErrorMe = tracker.m_projectionErrorMe;
271 m_projectionErrorKernelSize = tracker.m_projectionErrorKernelSize;
272 m_SobelX = tracker.m_SobelX;
273 m_SobelY = tracker.m_SobelY;
274 m_projectionErrorDisplay = tracker.m_projectionErrorDisplay;
275 m_projectionErrorDisplayLength = tracker.m_projectionErrorDisplayLength;
276 m_projectionErrorDisplayThickness = tracker.m_projectionErrorDisplayThickness;
277 m_projectionErrorCam = tracker.m_projectionErrorCam;
278 m_mask = tracker.m_mask;
279 m_I = tracker.m_I;
280 m_sodb_init_called = tracker.m_sodb_init_called;
281 m_rand = tracker.m_rand;
282 return *this;
283}
284
286{
287 for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_projectionErrorLines.begin();
288 it != m_projectionErrorLines.end(); ++it) {
289 vpMbtDistanceLine *l = *it;
290 if (l != nullptr)
291 delete l;
292 l = nullptr;
293 }
294
295 for (std::vector<vpMbtDistanceCylinder *>::const_iterator it = m_projectionErrorCylinders.begin();
296 it != m_projectionErrorCylinders.end(); ++it) {
297 vpMbtDistanceCylinder *cy = *it;
298 if (cy != nullptr)
299 delete cy;
300 cy = nullptr;
301 }
302
303 for (std::vector<vpMbtDistanceCircle *>::const_iterator it = m_projectionErrorCircles.begin();
304 it != m_projectionErrorCircles.end(); ++it) {
305 vpMbtDistanceCircle *ci = *it;
306 if (ci != nullptr)
307 delete ci;
308 ci = nullptr;
309 }
310#if defined(VISP_HAVE_COIN3D) && (COIN_MAJOR_VERSION >= 2)
311 if (m_sodb_init_called) {
312 // Cleanup memory allocated by Coin library used to load a vrml model
313 SoDB::finish();
314 }
315#endif
316}
317
318#ifdef VISP_HAVE_MODULE_GUI
319void vpMbTracker::initClick(const vpImage<unsigned char> *const I, const vpImage<vpRGBa> *const I_color,
320 const std::string &initFile, bool displayHelp, const vpHomogeneousMatrix &od_M_o)
321{
322 vpHomogeneousMatrix last_cMo;
323 vpPoseVector init_pos;
324 vpImagePoint ip;
326
327 std::string ext = ".init";
328 std::string str_pose = "";
329 size_t pos = initFile.rfind(ext);
330
331 // Load the last poses from files
332 std::fstream finitpos;
333 std::stringstream ss;
334 if (poseSavingFilename.empty()) {
335 if (pos != std::string::npos)
336 str_pose = initFile.substr(0, pos) + ".0.pos";
337 else
338 str_pose = initFile + ".0.pos";
339
340 finitpos.open(str_pose.c_str(), std::ios::in);
341 ss << str_pose;
342 }
343 else {
344 finitpos.open(poseSavingFilename.c_str(), std::ios::in);
345 ss << poseSavingFilename;
346 }
347 if (finitpos.fail()) {
348 std::cout << "Cannot read " << ss.str() << std::endl << "cMo set to identity" << std::endl;
349 last_cMo.eye();
350 }
351 else {
352 for (unsigned int i = 0; i < 6; i += 1) {
353 finitpos >> init_pos[i];
354 }
355
356 finitpos.close();
357 last_cMo.buildFrom(init_pos);
358
359 std::cout << "Tracker initial pose read from " << ss.str() << ": " << std::endl << last_cMo << std::endl;
360
361 if (I) {
363 display(*I, last_cMo, m_cam, vpColor::green, 1, true);
364 vpDisplay::displayFrame(*I, last_cMo, m_cam, 0.05, vpColor::green);
366 }
367 else {
368 vpDisplay::display(*I_color);
369 display(*I_color, last_cMo, m_cam, vpColor::green, 1, true);
370 vpDisplay::displayFrame(*I_color, last_cMo, m_cam, 0.05, vpColor::green);
371 vpDisplay::flush(*I_color);
372 }
373
374 std::cout << "No modification : left click " << std::endl;
375 std::cout << "Modify initial pose : right click " << std::endl;
376
377 if (I) {
378 int display_scaling = vpDisplay::getDownScalingFactor(*I);
379 vpDisplay::displayText(*I, 15*display_scaling, 10*display_scaling, "Left click to validate, right click to modify initial pose", vpColor::red);
380
382
383 while (!vpDisplay::getClick(*I, ip, button)) {
384 }
385 }
386 else {
387 int display_scaling = vpDisplay::getDownScalingFactor(*I_color);
388 vpDisplay::displayText(*I_color, 15*display_scaling, 10*display_scaling, "Left click to validate, right click to modify initial pose",
390
391 vpDisplay::flush(*I_color);
392
393 while (!vpDisplay::getClick(*I_color, ip, button)) {
394 }
395 }
396 }
397
398 if (!finitpos.fail() && button == vpMouseButton::button1) {
399 m_cMo = last_cMo;
400 }
401 else {
402 vpDisplay *d_help = nullptr;
403
404 if (I) {
407 }
408 else {
409 vpDisplay::display(*I_color);
410 vpDisplay::flush(*I_color);
411 }
412
413 vpPose pose;
414
415 pose.clearPoint();
416
417#ifdef VISP_HAVE_MODULE_IO
418 // Display window creation and initialisation
419 try {
420 if (displayHelp) {
421 const std::string imgExtVec[] = { ".ppm", ".pgm", ".jpg", ".jpeg", ".png" };
422 std::string dispF;
423 bool foundHelpImg = false;
424 if (pos != std::string::npos) {
425 for (size_t i = 0; i < 5 && !foundHelpImg; i++) {
426 dispF = initFile.substr(0, pos) + imgExtVec[i];
427 foundHelpImg = vpIoTools::checkFilename(dispF);
428 }
429 }
430 else {
431 for (size_t i = 0; i < 5 && !foundHelpImg; i++) {
432 dispF = initFile + imgExtVec[i];
433 foundHelpImg = vpIoTools::checkFilename(dispF);
434 }
435 }
436
437 if (foundHelpImg) {
438 std::cout << "Load image to help initialization: " << dispF << std::endl;
439
442 vpImage<vpRGBa> Iref;
443 vpImageIo::read(Iref, dispF);
444#if defined(VISP_HAVE_DISPLAY)
445 const int winXPos = I != nullptr ? I->display->getWindowXPosition() : I_color->display->getWindowXPosition();
446 const int winYPos = I != nullptr ? I->display->getWindowYPosition() : I_color->display->getWindowYPosition();
447 unsigned int width = I != nullptr ? I->getWidth() : I_color->getWidth();
448 d_help->init(Iref, winXPos + static_cast<int>(width) + 80, winYPos, "Where to initialize...");
449 vpDisplay::display(Iref);
450 vpDisplay::flush(Iref);
451#endif
454 }
455 catch (...) {
456 if (d_help != nullptr) {
457 delete d_help;
458 d_help = nullptr;
459 }
461#else //#ifdef VISP_HAVE_MODULE_IO
462 (void)(displayHelp);
463#endif //#ifdef VISP_HAVE_MODULE_IO
465 // Clear string stream that previously contained the path to the "object.0.pos" file.
466 ss.str(std::string());
468 // file parser
469 // number of points
470 // X Y Z
471 // X Y Z
472 if (pos != std::string::npos) {
473 ss << initFile;
474 }
475 else {
476 ss << initFile;
477 ss << ".init";
478 }
479
480 std::vector<vpPoint> points_3D;
481 std::vector<std::string> vectorOfInitFilename;
482 m_nbInitPoints = 0;
483 loadInitFile(ss.str(), vectorOfInitFilename, true, od_M_o, points_3D);
484
485 bool isWellInit = false;
486 while (!isWellInit) {
487 std::vector<vpImagePoint> mem_ip;
488 for (unsigned int i = 0; i < points_3D.size(); i++) {
489 std::ostringstream text;
490 text << "Click on point " << i + 1;
491 if (I) {
492 int display_scaling = vpDisplay::getDownScalingFactor(*I);
494 vpDisplay::displayText(*I, 15*display_scaling, 10*display_scaling, text.str(), vpColor::red);
495 for (unsigned int k = 0; k < mem_ip.size(); k++) {
496 vpDisplay::displayCross(*I, mem_ip[k], 13*display_scaling, vpColor::green, 1);
497 }
499 }
500 else {
501 int display_scaling = vpDisplay::getDownScalingFactor(*I_color);
502 vpDisplay::display(*I_color);
503 vpDisplay::displayText(*I_color, 15*display_scaling, 10*display_scaling, text.str(), vpColor::red);
504 for (unsigned int k = 0; k < mem_ip.size(); k++) {
505 vpDisplay::displayCross(*I_color, mem_ip[k], 13*display_scaling, vpColor::green, 1);
506 }
507 vpDisplay::flush(*I_color);
508 }
509
510 std::cout << "Click on point " << i + 1 << " ";
511 double x = 0, y = 0;
512 if (I) {
513 vpDisplay::getClick(*I, ip);
514 mem_ip.push_back(ip);
516 }
517 else {
518 vpDisplay::getClick(*I_color, ip);
519 mem_ip.push_back(ip);
520 vpDisplay::flush(*I_color);
521 }
523 points_3D[i].set_x(x);
524 points_3D[i].set_y(y);
525
526 std::cout << "with 2D coordinates: " << ip << std::endl;
527
528 pose.addPoint(points_3D[i]); // and added to the pose computation point list
529 }
530 if (I) {
533 }
534 else {
535 vpDisplay::flush(*I_color);
536 vpDisplay::display(*I_color);
537 }
538
540
541 if (I) {
542
543 display(*I, m_cMo, m_cam, vpColor::green, 1, true);
544 int display_scaling = vpDisplay::getDownScalingFactor(*I);
545 vpDisplay::displayText(*I, 15*display_scaling, 10*display_scaling, "Left click to validate, right click to re initialize object", vpColor::red);
546
548
549 button = vpMouseButton::button1;
550 while (!vpDisplay::getClick(*I, ip, button)) {
551 }
552
553 if (button == vpMouseButton::button1) {
554 isWellInit = true;
555 }
556 else {
557 pose.clearPoint();
560 }
561 }
562 else {
563 display(*I_color, m_cMo, m_cam, vpColor::green, 1, true);
564 int display_scaling = vpDisplay::getDownScalingFactor(*I_color);
565 vpDisplay::displayText(*I_color, 15*display_scaling, 10*display_scaling, "Left click to validate, right click to re initialize object",
567
568 vpDisplay::flush(*I_color);
569
570 button = vpMouseButton::button1;
571 while (!vpDisplay::getClick(*I_color, ip, button)) {
572 }
573
574 if (button == vpMouseButton::button1) {
575 isWellInit = true;
576 }
577 else {
578 pose.clearPoint();
579 vpDisplay::display(*I_color);
580 vpDisplay::flush(*I_color);
581 }
582 }
583 }
584 if (I)
586 else
588
589 // save the pose into file
590 if (poseSavingFilename.empty())
591 savePose(str_pose);
592 else
594
595 if (d_help != nullptr) {
596 delete d_help;
597 d_help = nullptr;
598 }
599 }
600
601 std::cout << "cMo : " << std::endl << m_cMo << std::endl;
602
603 if (I)
604 init(*I);
605 else {
606 vpImageConvert::convert(*I_color, m_I);
607 init(m_I);
608 }
609}
610
619void vpMbTracker::loadInitFile(const std::string &init_file, std::vector<std::string> &vectorOfInitFilename,
620 bool parent, const vpHomogeneousMatrix &od_M_o, std::vector<vpPoint> &points_3D)
621{
622 const unsigned int m_maxInitPoints = 100; // arbitrary value
623 std::ifstream finit;
624 std::cout << "Load 3D points from: " << init_file << std::endl;
625
626#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
627 finit.open(init_file);
628#else
629 finit.open(init_file.c_str());
630#endif
631 if (finit.fail()) {
632 std::cout << "Cannot read init file: " << init_file << std::endl;
633 throw vpException(vpException::ioError, "Cannot open model-based tracker init file %s", init_file.c_str());
634 }
635 // skip lines starting with # as comment
637
638 vectorOfInitFilename.push_back(init_file);
639
641 std::string line;
642 const std::string prefix_load = "load";
643 char c;
644
645 finit.get(c);
646 finit.unget();
647 bool header = false;
648 while ((c == 'l') || (c == 'L')) {
649 getline(finit, line);
650
651 // Test if "load" keyword is found
652 if (!line.compare(0, prefix_load.size(), prefix_load)) {
653 // remove "load("
654 std::string paramsStr = line.substr(5);
655 // get parameters inside load()
656 paramsStr = paramsStr.substr(0, paramsStr.find_first_of(")"));
657 // split by comma
658 std::vector<std::string> params = vpIoTools::splitChain(paramsStr, ",");
659 // remove whitespaces
660 for (size_t i = 0; i < params.size(); i++) {
661 params[i] = vpIoTools::trim(params[i]);
662 }
663 if (!params.empty()) {
664 // Get the loaded model pathname
665 std::string headerPathRead = params[0];
666 headerPathRead = headerPathRead.substr(1);
667 headerPathRead = headerPathRead.substr(0, headerPathRead.find_first_of("\""));
668
669 std::string headerPath = headerPathRead;
670 if (!vpIoTools::isAbsolutePathname(headerPathRead)) {
671 std::string parentDirectory = vpIoTools::getParent(init_file);
672 headerPath = vpIoTools::createFilePath(parentDirectory, headerPathRead);
673 }
674
675 // Normalize path
676 headerPath = vpIoTools::path(headerPath);
677
678 // Get real path
679 headerPath = vpIoTools::getAbsolutePathname(headerPath);
680
681 vpHomogeneousMatrix o_M_o_from_init;
684 for (size_t i = 1; i < params.size(); i++) {
685 std::string param = params[i];
686 {
687 const std::string prefix = "t=[";
688 if (!param.compare(0, prefix.size(), prefix)) {
689 param = param.substr(prefix.size());
690 param = param.substr(0, param.find_first_of("]"));
691
692 std::vector<std::string> values = vpIoTools::splitChain(param, ";");
693 if (values.size() == 3) {
694 t[0] = atof(values[0].c_str());
695 t[1] = atof(values[1].c_str());
696 t[2] = atof(values[2].c_str());
697 }
698 }
699 }
700 {
701 const std::string prefix = "tu=[";
702 if (!param.compare(0, prefix.size(), prefix)) {
703 param = param.substr(prefix.size());
704 param = param.substr(0, param.find_first_of("]"));
705
706 std::vector<std::string> values = vpIoTools::splitChain(param, ";");
707 if (values.size() == 3) {
709 for (size_t j = 0; j < values.size(); j++) {
710 std::string value = values[j];
711 bool radian = true;
712 size_t unitPos = value.find("deg");
713 if (unitPos != std::string::npos) {
714 value = value.substr(0, unitPos);
715 radian = false;
716 }
717
718 unitPos = value.find("rad");
719 if (unitPos != std::string::npos) {
720 value = value.substr(0, unitPos);
721 }
722 tu[static_cast<unsigned int>(j)] = !radian ? vpMath::rad(atof(value.c_str())) : atof(value.c_str());
723 R.buildFrom(tu);
724 }
725 }
726 }
727 }
728 {
729 const std::string prefix = "R=[";
730 if (!param.compare(0, prefix.size(), prefix)) {
731 param = param.substr(prefix.size());
732 param = param.substr(0, param.find_first_of("]"));
733
734 std::vector<std::string> values = vpIoTools::splitChain(param, ";");
735 if (values.size() == 9) {
736 R[0][0] = atof(values[0].c_str());
737 R[0][1] = atof(values[1].c_str());
738 R[0][2] = atof(values[2].c_str());
739 R[1][0] = atof(values[3].c_str());
740 R[1][1] = atof(values[4].c_str());
741 R[1][2] = atof(values[5].c_str());
742 R[2][0] = atof(values[6].c_str());
743 R[2][1] = atof(values[7].c_str());
744 R[2][2] = atof(values[8].c_str());
745 }
746 }
747 }
748 }
749 o_M_o_from_init.buildFrom(t, R);
750 bool cyclic = false;
751 for (std::vector<std::string>::const_iterator it = vectorOfInitFilename.begin();
752 it != vectorOfInitFilename.end() && !cyclic; ++it) {
753 if (headerPath == *it) {
754 cyclic = true;
755 }
756 }
757
758 if (!cyclic) {
759 if (vpIoTools::checkFilename(headerPath)) {
760 header = true;
761 loadInitFile(headerPath, vectorOfInitFilename, false, od_M_o * o_M_o_from_init, points_3D);
762 }
763 else {
764 finit.close();
765 throw vpException(vpException::ioError, "file cannot be open");
766 }
767 }
768 else {
769 std::cout << "WARNING Cyclic dependency detected with file " << headerPath << " declared in " << init_file
770 << std::endl;
771 }
772 }
773 }
774 try {
776 }
777 catch (...) {
778 if (finit.eof()) {
779 return;
780 }
781 }
782 finit.get(c);
783 finit.unget();
784 }
785
787 unsigned int nb_points = 0;
788 finit >> nb_points;
789 finit.ignore(std::numeric_limits<std::streamsize>::max(), finit.widen('\n')); // skip the rest of the line
790
791 if (parent && !header) {
792#if defined(VISP_HAVE_THREADS)
793 std::lock_guard<std::mutex> lock(g_mutex_cout);
794#endif
795 std::cout << "> " << nb_points << " init points" << std::endl;
796 }
797 if (nb_points) {
798 std::cout << "Number of 3D points for interactive init: " << nb_points << std::endl;
799 }
800
801 if (nb_points > m_maxInitPoints) {
802 finit.close();
803 throw vpException(vpException::badValue, "In %s file, the number of 3D points exceed the max allowed (%d)",
804 init_file.c_str(), m_maxInitPoints);
805 }
806 if (nb_points == 0 && !header) {
807 finit.close();
808 throw vpException(vpException::badValue, "in vpMbTracker::loadInitFile() -> no points are defined");
809 }
810 vpPoint P;
811 for (unsigned int i = 0; i < nb_points; i++) {
812 // skip lines starting with # as comment
814
815 vpColVector pt_3d(4, 1.0);
816 finit >> pt_3d[0];
817 finit >> pt_3d[1];
818 finit >> pt_3d[2];
819 finit.ignore(256, '\n'); // skip the rest of the line
820
821 vpColVector pt_3d_tf = od_M_o * pt_3d;
822 std::cout << "Point " << i + 1 + m_nbInitPoints << " with 3D coordinates: " << pt_3d_tf[0] << " " << pt_3d_tf[1] << " "
823 << pt_3d_tf[2] << std::endl;
824
825 P.setWorldCoordinates(pt_3d_tf[0], pt_3d_tf[1], pt_3d_tf[2]); // (X,Y,Z)
826
827 points_3D.push_back(P);
828 }
829 m_nbInitPoints += nb_points;
830 finit.close();
831}
832
834 Initialise the tracker by clicking in the image on the pixels that
835 correspond to the 3D points whose coordinates are extracted from a file. In
836 this file, comments starting with # character are allowed. Notice that 3D
837 point coordinates are expressed in meter in the object frame with their X, Y
838 and Z values.
839
840 The structure of this file is the following:
841
842 \verbatim
843 # 3D point coordinates
844 4 # Number of points in the file (minimum is four)
845 0.01 0.01 0.01 # \
846 ... # | 3D coordinates in the object frame (X, Y, Z)
847 0.01 -0.01 -0.01 # /
848 \endverbatim
849
850 \param I : Input grayscale image where the user has to click.
851 \param initFile : File containing the coordinates of at least 4 3D points
852 the user has to click in the image. This file should have .init extension
853 (ie teabox.init).
854 \param displayHelp : Optional display of an image (.ppm, .pgm, .jpg, .jpeg, .png) that
855 should have the same generic name as the init file (ie teabox.ppm or teabox.png). This
856 image may be used to show where to click. This functionality is only
857 available if visp_io module is used.
858 \param T : optional transformation matrix to transform
859 3D points expressed in the original object frame to the desired object frame.
860
861 \exception vpException::ioError : The file specified in \e initFile doesn't
862 exist.
863*/
864void vpMbTracker::initClick(const vpImage<unsigned char> &I, const std::string &initFile, bool displayHelp,
865 const vpHomogeneousMatrix &T)
867 initClick(&I, nullptr, initFile, displayHelp, T);
868}
869
870/*!
871 Initialise the tracker by clicking in the image on the pixels that
872 correspond to the 3D points whose coordinates are extracted from a file. In
873 this file, comments starting with # character are allowed. Notice that 3D
874 point coordinates are expressed in meter in the object frame with their X, Y
875 and Z values.
876
877 The structure of this file is the following:
878
879 \verbatim
880 # 3D point coordinates
881 4 # Number of points in the file (minimum is four)
882 0.01 0.01 0.01 # \
883 ... # | 3D coordinates in the object frame (X, Y, Z)
884 0.01 -0.01 -0.01 # /
885 \endverbatim
886
887 \param I_color : Input color image where the user has to click.
888 \param initFile : File containing the coordinates of at least 4 3D points
889 the user has to click in the image. This file should have .init extension
890 (ie teabox.init).
891 \param displayHelp : Optional display of an image (.ppm, .pgm, .jpg, .jpeg, .png) that
892 should have the same generic name as the init file (ie teabox.ppm or teabox.png). This
893 image may be used to show where to click. This functionality is only
894 available if visp_io module is used.
895 \param T : optional transformation matrix to transform
896 3D points expressed in the original object frame to the desired object frame.
897
898 \exception vpException::ioError : The file specified in \e initFile doesn't
899 exist.
900*/
901void vpMbTracker::initClick(const vpImage<vpRGBa> &I_color, const std::string &initFile, bool displayHelp,
902 const vpHomogeneousMatrix &T)
903{
904 initClick(nullptr, &I_color, initFile, displayHelp, T);
905}
906
907void vpMbTracker::initClick(const vpImage<unsigned char> *const I, const vpImage<vpRGBa> *const I_color,
908 const std::vector<vpPoint> &points3D_list, const std::string &displayFile)
909{
910 if (I) {
913 }
914 else {
915 vpDisplay::display(*I_color);
916 vpDisplay::flush(*I_color);
917 }
918
919 vpDisplay *d_help = nullptr;
920
921 vpPose pose;
922 std::vector<vpPoint> P;
923 for (unsigned int i = 0; i < points3D_list.size(); i++)
924 P.push_back(vpPoint(points3D_list[i].get_oX(), points3D_list[i].get_oY(), points3D_list[i].get_oZ()));
925
926#ifdef VISP_HAVE_MODULE_IO
927 vpImage<vpRGBa> Iref;
928 // Display window creation and initialisation
929 if (vpIoTools::checkFilename(displayFile)) {
930 try {
931 std::cout << "Load image to help initialization: " << displayFile << std::endl;
932#if defined(VISP_HAVE_X11)
933 d_help = new vpDisplayX;
934#elif defined(VISP_HAVE_GDI)
935 d_help = new vpDisplayGDI;
936#elif defined VISP_HAVE_OPENCV
937 d_help = new vpDisplayOpenCV;
938#endif
939
940 vpImageIo::read(Iref, displayFile);
941#if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV)
942 if (I) {
943 d_help->init(Iref, I->display->getWindowXPosition() + static_cast<int>(I->getWidth()) + 80, I->display->getWindowYPosition(),
944 "Where to initialize...");
945 }
946 else {
947 d_help->init(Iref, I_color->display->getWindowXPosition() + static_cast<int>(I_color->getWidth()) + 80,
948 I_color->display->getWindowYPosition(), "Where to initialize...");
949 }
950 vpDisplay::display(Iref);
951 vpDisplay::flush(Iref);
952#endif
953 }
954 catch (...) {
955 if (d_help != nullptr) {
956 delete d_help;
957 d_help = nullptr;
958 }
959 }
960 }
961#else //#ifdef VISP_HAVE_MODULE_IO
962 (void)(displayFile);
963#endif //#ifdef VISP_HAVE_MODULE_IO
964
965 vpImagePoint ip;
966 bool isWellInit = false;
967 while (!isWellInit) {
968 for (unsigned int i = 0; i < points3D_list.size(); i++) {
969 std::cout << "Click on point " << i + 1 << std::endl;
970 double x = 0, y = 0;
971 if (I) {
972 vpDisplay::getClick(*I, ip);
975 }
976 else {
977 vpDisplay::getClick(*I_color, ip);
978 vpDisplay::displayCross(*I_color, ip, 5, vpColor::green);
979 vpDisplay::flush(*I_color);
980 }
982 P[i].set_x(x);
983 P[i].set_y(y);
984
985 std::cout << "Click on point " << ip << std::endl;
986
987 if (I) {
988 vpDisplay::displayPoint(*I, ip, vpColor::green); // display target point
989 }
990 else {
991 vpDisplay::displayPoint(*I_color, ip, vpColor::green); // display target point
992 }
993 pose.addPoint(P[i]); // and added to the pose computation point list
994 }
995 if (I) {
997 }
998 else {
999 vpDisplay::flush(*I_color);
1000 }
1001
1003
1004 if (I) {
1005 display(*I, m_cMo, m_cam, vpColor::green, 1, true);
1006 int display_scaling = vpDisplay::getDownScalingFactor(*I);
1007 vpDisplay::displayText(*I, 15*display_scaling, 10*display_scaling, "left click to validate, right click to re initialize object", vpColor::red);
1008
1009 vpDisplay::flush(*I);
1010
1012 while (!vpDisplay::getClick(*I, ip, button)) {
1013 }
1014
1015 if (button == vpMouseButton::button1) {
1016 isWellInit = true;
1017 }
1018 else {
1019 pose.clearPoint();
1021 vpDisplay::flush(*I);
1022 }
1023 }
1024 else {
1025 display(*I_color, m_cMo, m_cam, vpColor::green, 1, true);
1026 int display_scaling = vpDisplay::getDownScalingFactor(*I_color);
1027 vpDisplay::displayText(*I_color, 15*display_scaling, 10*display_scaling, "left click to validate, right click to re initialize object",
1028 vpColor::red);
1029
1030 vpDisplay::flush(*I_color);
1031
1033 while (!vpDisplay::getClick(*I_color, ip, button)) {
1034 }
1035
1036 if (button == vpMouseButton::button1) {
1037 isWellInit = true;
1038 }
1039 else {
1040 pose.clearPoint();
1041 vpDisplay::display(*I_color);
1042 vpDisplay::flush(*I_color);
1043 }
1044 }
1045 }
1046
1047 if (I) {
1049 }
1050 else {
1052 }
1053
1054 if (d_help != nullptr) {
1055 delete d_help;
1056 d_help = nullptr;
1057 }
1058
1059 if (I)
1060 init(*I);
1061 else {
1062 vpImageConvert::convert(*I_color, m_I);
1063 init(m_I);
1064 }
1065}
1066
1078void vpMbTracker::initClick(const vpImage<unsigned char> &I, const std::vector<vpPoint> &points3D_list,
1079 const std::string &displayFile)
1080{
1081 initClick(&I, nullptr, points3D_list, displayFile);
1082}
1083
1095void vpMbTracker::initClick(const vpImage<vpRGBa> &I_color, const std::vector<vpPoint> &points3D_list,
1096 const std::string &displayFile)
1097{
1098 initClick(nullptr, &I_color, points3D_list, displayFile);
1099}
1100#endif //#ifdef VISP_HAVE_MODULE_GUI
1101
1103 const std::string &initFile)
1104{
1105 std::stringstream ss;
1106 std::fstream finit;
1107
1108 std::string ext = ".init";
1109 size_t pos = initFile.rfind(ext);
1110
1111 if (pos == initFile.size() - ext.size() && pos != 0) {
1112 ss << initFile;
1113 }
1114 else {
1115 ss << initFile;
1116 ss << ".init";
1117 }
1118
1119 std::cout << "Load 2D/3D points from: " << ss.str() << std::endl;
1120 finit.open(ss.str().c_str(), std::ios::in);
1121 if (finit.fail()) {
1122 std::cout << "cannot read " << ss.str() << std::endl;
1123 throw vpException(vpException::ioError, "Cannot open model-based tracker init file %s", ss.str().c_str());
1124 }
1125
1126 //********
1127 // Read 3D points coordinates
1128 //********
1129 char c;
1130 // skip lines starting with # as comment
1131 finit.get(c);
1132 while (!finit.fail() && (c == '#')) {
1133 finit.ignore(256, '\n');
1134 finit.get(c);
1135 }
1136 finit.unget();
1137
1138 unsigned int n3d;
1139 finit >> n3d;
1140 finit.ignore(256, '\n'); // skip the rest of the line
1141 std::cout << "Number of 3D points " << n3d << std::endl;
1142 if (n3d > 100000) {
1143 throw vpException(vpException::badValue, "In %s file, the number of 3D points exceed the max allowed",
1144 ss.str().c_str());
1145 }
1146
1147 vpPoint *P = new vpPoint[n3d];
1148 for (unsigned int i = 0; i < n3d; i++) {
1149 // skip lines starting with # as comment
1150 finit.get(c);
1151 while (!finit.fail() && (c == '#')) {
1152 finit.ignore(256, '\n');
1153 finit.get(c);
1154 }
1155 finit.unget();
1156 double X, Y, Z;
1157 finit >> X;
1158 finit >> Y;
1159 finit >> Z;
1160 finit.ignore(256, '\n'); // skip the rest of the line
1161
1162 std::cout << "Point " << i + 1 << " with 3D coordinates: " << X << " " << Y << " " << Z << std::endl;
1163 P[i].setWorldCoordinates(X, Y, Z); // (X,Y,Z)
1164 }
1165
1166 //********
1167 // Read 3D points coordinates
1168 //********
1169 // skip lines starting with # as comment
1170 finit.get(c);
1171 while (!finit.fail() && (c == '#')) {
1172 finit.ignore(256, '\n');
1173 finit.get(c);
1174 }
1175 finit.unget();
1176
1177 unsigned int n2d;
1178 finit >> n2d;
1179 finit.ignore(256, '\n'); // skip the rest of the line
1180 std::cout << "Number of 2D points " << n2d << std::endl;
1181 if (n2d > 100000) {
1182 delete[] P;
1183 throw vpException(vpException::badValue, "In %s file, the number of 2D points exceed the max allowed",
1184 ss.str().c_str());
1185 }
1186
1187 if (n3d != n2d) {
1188 delete[] P;
1190 "In %s file, number of 2D points %d and number of 3D "
1191 "points %d are not equal",
1192 ss.str().c_str(), n2d, n3d);
1193 }
1194
1195 vpPose pose;
1196 for (unsigned int i = 0; i < n2d; i++) {
1197 // skip lines starting with # as comment
1198 finit.get(c);
1199 while (!finit.fail() && (c == '#')) {
1200 finit.ignore(256, '\n');
1201 finit.get(c);
1202 }
1203 finit.unget();
1204 double u, v, x = 0, y = 0;
1205 finit >> v;
1206 finit >> u;
1207 finit.ignore(256, '\n'); // skip the rest of the line
1208
1209 vpImagePoint ip(v, u);
1210 std::cout << "Point " << i + 1 << " with 2D coordinates: " << ip << std::endl;
1212 P[i].set_x(x);
1213 P[i].set_y(y);
1214 pose.addPoint(P[i]);
1215 }
1216
1217 finit.close();
1218
1220
1221 delete[] P;
1222
1223 if (I) {
1224 init(*I);
1225 }
1226 else {
1227 vpImageConvert::convert(*I_color, m_I);
1228 init(m_I);
1229 }
1230}
1231
1256void vpMbTracker::initFromPoints(const vpImage<unsigned char> &I, const std::string &initFile)
1257{
1258 initFromPoints(&I, nullptr, initFile);
1259}
1260
1285void vpMbTracker::initFromPoints(const vpImage<vpRGBa> &I_color, const std::string &initFile)
1286{
1287 initFromPoints(nullptr, &I_color, initFile);
1288}
1289
1291 const std::vector<vpImagePoint> &points2D_list,
1292 const std::vector<vpPoint> &points3D_list)
1293{
1294 if (points2D_list.size() != points3D_list.size())
1295 vpERROR_TRACE("vpMbTracker::initFromPoints(), Number of 2D points "
1296 "different to the number of 3D points.");
1297
1298 size_t size = points3D_list.size();
1299 std::vector<vpPoint> P;
1300 vpPose pose;
1301
1302 for (size_t i = 0; i < size; i++) {
1303 P.push_back(vpPoint(points3D_list[i].get_oX(), points3D_list[i].get_oY(), points3D_list[i].get_oZ()));
1304 double x = 0, y = 0;
1305 vpPixelMeterConversion::convertPoint(m_cam, points2D_list[i], x, y);
1306 P[i].set_x(x);
1307 P[i].set_y(y);
1308 pose.addPoint(P[i]);
1309 }
1310
1312
1313 if (I) {
1314 init(*I);
1315 }
1316 else {
1317 vpImageConvert::convert(*I_color, m_I);
1318 init(m_I);
1319 }
1320}
1321
1330void vpMbTracker::initFromPoints(const vpImage<unsigned char> &I, const std::vector<vpImagePoint> &points2D_list,
1331 const std::vector<vpPoint> &points3D_list)
1332{
1333 initFromPoints(&I, nullptr, points2D_list, points3D_list);
1334}
1335
1344void vpMbTracker::initFromPoints(const vpImage<vpRGBa> &I_color, const std::vector<vpImagePoint> &points2D_list,
1345 const std::vector<vpPoint> &points3D_list)
1346{
1347 initFromPoints(nullptr, &I_color, points2D_list, points3D_list);
1348}
1349
1350void vpMbTracker::initFromPose(const vpImage<unsigned char> *const I, const vpImage<vpRGBa> *const I_color,
1351 const std::string &initFile)
1352{
1353 std::stringstream ss;
1354 std::fstream finit;
1355 vpPoseVector init_pos;
1356
1357 std::string ext = ".pos";
1358 size_t pos = initFile.rfind(ext);
1359
1360 if (pos == initFile.size() - ext.size() && pos != 0) {
1361 ss << initFile;
1362 }
1363 else {
1364 ss << initFile;
1365 ss << ".pos";
1366 }
1367
1368 finit.open(ss.str().c_str(), std::ios::in);
1369 if (finit.fail()) {
1370 std::cout << "Cannot read " << ss.str() << std::endl;
1371 throw vpException(vpException::ioError, "cannot read init file");
1372 }
1373
1374 for (unsigned int i = 0; i < 6; i += 1) {
1375 finit >> init_pos[i];
1376 }
1377
1378 m_cMo.buildFrom(init_pos);
1379
1380 if (I) {
1381 init(*I);
1382 }
1383 else {
1384 vpImageConvert::convert(*I_color, m_I);
1385 init(m_I);
1386 }
1387}
1388
1407void vpMbTracker::initFromPose(const vpImage<unsigned char> &I, const std::string &initFile)
1408{
1409 initFromPose(&I, nullptr, initFile);
1410}
1411
1430void vpMbTracker::initFromPose(const vpImage<vpRGBa> &I_color, const std::string &initFile)
1431{
1432 initFromPose(nullptr, &I_color, initFile);
1433}
1434
1442{
1443 m_cMo = cMo;
1444 init(I);
1445}
1446
1454{
1455 m_cMo = cMo;
1456 vpImageConvert::convert(I_color, m_I);
1457 init(m_I);
1458}
1459
1467{
1468 vpHomogeneousMatrix _cMo(cPo);
1469 initFromPose(I, _cMo);
1470}
1471
1479{
1480 vpHomogeneousMatrix _cMo(cPo);
1481 vpImageConvert::convert(I_color, m_I);
1482 initFromPose(m_I, _cMo);
1483}
1484
1490void vpMbTracker::savePose(const std::string &filename) const
1491{
1492 vpPoseVector init_pos;
1493 std::fstream finitpos;
1494 finitpos.open(filename.c_str(), std::ios::out);
1495
1496 init_pos.buildFrom(m_cMo);
1497 finitpos << init_pos;
1498 finitpos.close();
1499}
1500
1501void vpMbTracker::addPolygon(const std::vector<vpPoint> &corners, int idFace, const std::string &polygonName,
1502 bool useLod, double minPolygonAreaThreshold, double minLineLengthThreshold)
1503{
1504 std::vector<vpPoint> corners_without_duplicates;
1505 corners_without_duplicates.push_back(corners[0]);
1506 for (unsigned int i = 0; i < corners.size() - 1; i++) {
1507 if (std::fabs(corners[i].get_oX() - corners[i + 1].get_oX()) >
1508 std::fabs(corners[i].get_oX()) * std::numeric_limits<double>::epsilon() ||
1509 std::fabs(corners[i].get_oY() - corners[i + 1].get_oY()) >
1510 std::fabs(corners[i].get_oY()) * std::numeric_limits<double>::epsilon() ||
1511 std::fabs(corners[i].get_oZ() - corners[i + 1].get_oZ()) >
1512 std::fabs(corners[i].get_oZ()) * std::numeric_limits<double>::epsilon()) {
1513 corners_without_duplicates.push_back(corners[i + 1]);
1514 }
1515 }
1516
1517 vpMbtPolygon polygon;
1518 polygon.setNbPoint(static_cast<unsigned int>(corners_without_duplicates.size()));
1519 polygon.setIndex(static_cast<int>(idFace));
1520 polygon.setName(polygonName);
1521 polygon.setLod(useLod);
1522
1523 // //if(minPolygonAreaThreshold != -1.0) {
1524 // if(std::fabs(minPolygonAreaThreshold + 1.0) >
1525 // std::fabs(minPolygonAreaThreshold)*std::numeric_limits<double>::epsilon())
1526 // {
1527 // polygon.setMinPolygonAreaThresh(minPolygonAreaThreshold);
1528 // }
1529 //
1530 // //if(minLineLengthThreshold != -1.0) {
1531 // if(std::fabs(minLineLengthThreshold + 1.0) >
1532 // std::fabs(minLineLengthThreshold)*std::numeric_limits<double>::epsilon())
1533 // {
1534 // polygon.setMinLineLengthThresh(minLineLengthThreshold);
1535 // }
1536
1537 polygon.setMinPolygonAreaThresh(minPolygonAreaThreshold);
1538 polygon.setMinLineLengthThresh(minLineLengthThreshold);
1539
1540 for (unsigned int j = 0; j < corners_without_duplicates.size(); j++) {
1541 polygon.addPoint(j, corners_without_duplicates[j]);
1542 }
1543
1544 faces.addPolygon(&polygon);
1545
1547 faces.getPolygon().back()->setClipping(clippingFlag);
1548
1550 faces.getPolygon().back()->setNearClippingDistance(distNearClip);
1551
1553 faces.getPolygon().back()->setFarClippingDistance(distFarClip);
1554}
1555
1556void vpMbTracker::addPolygon(const vpPoint &p1, const vpPoint &p2, const vpPoint &p3, double radius, int idFace,
1557 const std::string &polygonName, bool useLod, double minPolygonAreaThreshold)
1558{
1559 vpMbtPolygon polygon;
1560 polygon.setNbPoint(4);
1561 polygon.setName(polygonName);
1562 polygon.setLod(useLod);
1563
1564 // //if(minPolygonAreaThreshold != -1.0) {
1565 // if(std::fabs(minPolygonAreaThreshold + 1.0) >
1566 // std::fabs(minPolygonAreaThreshold)*std::numeric_limits<double>::epsilon())
1567 // {
1568 // polygon.setMinPolygonAreaThresh(minPolygonAreaThreshold);
1569 // }
1570 polygon.setMinPolygonAreaThresh(minPolygonAreaThreshold);
1571 // Non sense to set minLineLengthThreshold for circle
1572 // but used to be coherent when applying LOD settings for all polygons
1574
1575 {
1576 // Create the 4 points of the circle bounding box
1577 vpPlane plane(p1, p2, p3, vpPlane::object_frame);
1578
1579 // Matrice de passage entre world et circle frame
1580 double norm_X = sqrt(vpMath::sqr(p2.get_oX() - p1.get_oX()) + vpMath::sqr(p2.get_oY() - p1.get_oY()) +
1581 vpMath::sqr(p2.get_oZ() - p1.get_oZ()));
1582 double norm_Y = sqrt(vpMath::sqr(plane.getA()) + vpMath::sqr(plane.getB()) + vpMath::sqr(plane.getC()));
1583 vpRotationMatrix wRc;
1584 vpColVector x(3), y(3), z(3);
1585 // X axis is P2-P1
1586 x[0] = (p2.get_oX() - p1.get_oX()) / norm_X;
1587 x[1] = (p2.get_oY() - p1.get_oY()) / norm_X;
1588 x[2] = (p2.get_oZ() - p1.get_oZ()) / norm_X;
1589 // Y axis is the normal of the plane
1590 y[0] = plane.getA() / norm_Y;
1591 y[1] = plane.getB() / norm_Y;
1592 y[2] = plane.getC() / norm_Y;
1593 // Z axis = X ^ Y
1594 z = vpColVector::crossProd(x, y);
1595 for (unsigned int i = 0; i < 3; i++) {
1596 wRc[i][0] = x[i];
1597 wRc[i][1] = y[i];
1598 wRc[i][2] = z[i];
1599 }
1600
1601 vpTranslationVector wtc(p1.get_oX(), p1.get_oY(), p1.get_oZ());
1602 vpHomogeneousMatrix wMc(wtc, wRc);
1603
1604 vpColVector c_p(4); // A point in the circle frame that is on the bbox
1605 c_p[0] = radius;
1606 c_p[1] = 0;
1607 c_p[2] = radius;
1608 c_p[3] = 1;
1609
1610 // Matrix to rotate a point by 90 deg around Y in the circle frame
1611 for (unsigned int i = 0; i < 4; i++) {
1612 vpColVector w_p(4); // A point in the word frame
1614 w_p = wMc * cMc_90 * c_p;
1615
1616 vpPoint w_P;
1617 w_P.setWorldCoordinates(w_p[0], w_p[1], w_p[2]);
1618
1619 polygon.addPoint(i, w_P);
1620 }
1621 }
1622
1623 polygon.setIndex(idFace);
1624 faces.addPolygon(&polygon);
1625
1627 faces.getPolygon().back()->setClipping(clippingFlag);
1628
1630 faces.getPolygon().back()->setNearClippingDistance(distNearClip);
1631
1633 faces.getPolygon().back()->setFarClippingDistance(distFarClip);
1634}
1635
1636void vpMbTracker::addPolygon(const vpPoint &p1, const vpPoint &p2, int idFace, const std::string &polygonName,
1637 bool useLod, double minLineLengthThreshold)
1638{
1639 // A polygon as a single line that corresponds to the revolution axis of the
1640 // cylinder
1641 vpMbtPolygon polygon;
1642 polygon.setNbPoint(2);
1643
1644 polygon.addPoint(0, p1);
1645 polygon.addPoint(1, p2);
1646
1647 polygon.setIndex(idFace);
1648 polygon.setName(polygonName);
1649 polygon.setLod(useLod);
1650
1651 // //if(minLineLengthThreshold != -1.0) {
1652 // if(std::fabs(minLineLengthThreshold + 1.0) >
1653 // std::fabs(minLineLengthThreshold)*std::numeric_limits<double>::epsilon())
1654 // {
1655 // polygon.setMinLineLengthThresh(minLineLengthThreshold);
1656 // }
1657 polygon.setMinLineLengthThresh(minLineLengthThreshold);
1658 // Non sense to set minPolygonAreaThreshold for cylinder
1659 // but used to be coherent when applying LOD settings for all polygons
1661
1662 faces.addPolygon(&polygon);
1663
1665 faces.getPolygon().back()->setClipping(clippingFlag);
1666
1668 faces.getPolygon().back()->setNearClippingDistance(distNearClip);
1669
1671 faces.getPolygon().back()->setFarClippingDistance(distFarClip);
1672}
1673
1674void vpMbTracker::addPolygon(const std::vector<std::vector<vpPoint> > &listFaces, int idFace,
1675 const std::string &polygonName, bool useLod, double minLineLengthThreshold)
1676{
1677 int id = idFace;
1678 for (unsigned int i = 0; i < listFaces.size(); i++) {
1679 vpMbtPolygon polygon;
1680 polygon.setNbPoint(static_cast<unsigned int>(listFaces[i].size()));
1681 for (unsigned int j = 0; j < listFaces[i].size(); j++)
1682 polygon.addPoint(j, listFaces[i][j]);
1683
1684 polygon.setIndex(id);
1685 polygon.setName(polygonName);
1686 polygon.setIsPolygonOriented(false);
1687 polygon.setLod(useLod);
1688 polygon.setMinLineLengthThresh(minLineLengthThreshold);
1690
1691 faces.addPolygon(&polygon);
1692
1694 faces.getPolygon().back()->setClipping(clippingFlag);
1695
1697 faces.getPolygon().back()->setNearClippingDistance(distNearClip);
1698
1700 faces.getPolygon().back()->setFarClippingDistance(distFarClip);
1701
1702 id++;
1703 }
1704}
1705
1721void vpMbTracker::loadModel(const std::string &modelFile, bool verbose, const vpHomogeneousMatrix &od_M_o)
1722{
1723 std::string::const_iterator it;
1724
1725 if (vpIoTools::checkFilename(modelFile)) {
1726 it = modelFile.end();
1727 if ((*(it - 1) == 'o' && *(it - 2) == 'a' && *(it - 3) == 'c' && *(it - 4) == '.') ||
1728 (*(it - 1) == 'O' && *(it - 2) == 'A' && *(it - 3) == 'C' && *(it - 4) == '.')) {
1729 std::vector<std::string> vectorOfModelFilename;
1730 int startIdFace = static_cast<int>(faces.size());
1731 nbPoints = 0;
1732 nbLines = 0;
1733 nbPolygonLines = 0;
1734 nbPolygonPoints = 0;
1735 nbCylinders = 0;
1736 nbCircles = 0;
1737 loadCAOModel(modelFile, vectorOfModelFilename, startIdFace, verbose, true, od_M_o);
1738 }
1739 else if ((*(it - 1) == 'l' && *(it - 2) == 'r' && *(it - 3) == 'w' && *(it - 4) == '.') ||
1740 (*(it - 1) == 'L' && *(it - 2) == 'R' && *(it - 3) == 'W' && *(it - 4) == '.')) {
1741 loadVRMLModel(modelFile);
1742 }
1743 else {
1744 throw vpException(vpException::ioError, "Error: File %s doesn't contain a cao or wrl model", modelFile.c_str());
1745 }
1746 }
1747 else {
1748 throw vpException(vpException::ioError, "Error: File %s doesn't exist", modelFile.c_str());
1749 }
1750
1751 this->modelInitialised = true;
1752 this->modelFileName = modelFile;
1753}
1754
1773void vpMbTracker::loadVRMLModel(const std::string &modelFile)
1774{
1775#ifdef VISP_HAVE_COIN3D
1776 m_sodb_init_called = true;
1777 SoDB::init(); // Call SoDB::finish() before ending the program.
1778
1779 SoInput in;
1780 SbBool ok = in.openFile(modelFile.c_str());
1781 SoVRMLGroup *sceneGraphVRML2;
1782
1783 if (!ok) {
1784 vpERROR_TRACE("can't open file to load model");
1785 throw vpException(vpException::fatalError, "can't open file to load model");
1786 }
1787
1788 if (!in.isFileVRML2()) {
1789 SoSeparator *sceneGraph = SoDB::readAll(&in);
1790 if (sceneGraph == nullptr) { /*return -1;*/
1791 }
1792 sceneGraph->ref();
1793
1794 SoToVRML2Action tovrml2;
1795 tovrml2.apply(sceneGraph);
1796
1797 sceneGraphVRML2 = tovrml2.getVRML2SceneGraph();
1798 sceneGraphVRML2->ref();
1799 sceneGraph->unref();
1800 }
1801 else {
1802 sceneGraphVRML2 = SoDB::readAllVRML(&in);
1803 if (sceneGraphVRML2 == nullptr) { /*return -1;*/
1804 }
1805 sceneGraphVRML2->ref();
1806 }
1807
1808 in.closeFile();
1809
1810 vpHomogeneousMatrix transform;
1811 int indexFace = static_cast<int>(faces.size());
1812 extractGroup(sceneGraphVRML2, transform, indexFace);
1813
1814 sceneGraphVRML2->unref();
1815#else
1816 vpERROR_TRACE("coin not detected with ViSP, cannot load model : %s", modelFile.c_str());
1817 throw vpException(vpException::fatalError, "coin not detected with ViSP, cannot load model");
1818#endif
1819}
1820
1826{
1827 char c;
1828
1829 fileId.get(c);
1830 while (!fileId.fail() && ((c == '#') || (c == '\n') || (c == '\r'))) {
1831 if (c == '#') {
1832 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n'));
1833 }
1834 fileId.get(c);
1835 }
1836 if (fileId.fail()) {
1837 throw(vpException(vpException::ioError, "Reached end of file"));
1838 }
1839 fileId.unget();
1840}
1841
1842std::map<std::string, std::string> vpMbTracker::parseParameters(std::string &endLine)
1843{
1844 std::map<std::string, std::string> mapOfParams;
1845
1846 bool exit = false;
1847 while (!endLine.empty() && !exit) {
1848 exit = true;
1849
1850 for (std::map<std::string, std::string>::const_iterator it = mapOfParameterNames.begin();
1851 it != mapOfParameterNames.end(); ++it) {
1852 endLine = vpIoTools::trim(endLine);
1853 std::string param(it->first + "=");
1854
1855 // Compare with a potential parameter
1856 if (endLine.compare(0, param.size(), param) == 0) {
1857 exit = false;
1858 endLine = endLine.substr(param.size());
1859
1860 bool parseQuote = false;
1861 if (it->second == "string") {
1862 // Check if the string is between quotes
1863 if (endLine.size() > 2 && endLine[0] == '"') {
1864 parseQuote = true;
1865 endLine = endLine.substr(1);
1866 size_t pos = endLine.find_first_of('"');
1867
1868 if (pos != std::string::npos) {
1869 mapOfParams[it->first] = endLine.substr(0, pos);
1870 endLine = endLine.substr(pos + 1);
1871 }
1872 else {
1873 parseQuote = false;
1874 }
1875 }
1876 }
1877
1878 if (!parseQuote) {
1879 // Deal with space or tabulation after parameter value to substring
1880 // to the next sequence
1881 size_t pos1 = endLine.find_first_of(' ');
1882 size_t pos2 = endLine.find_first_of('\t');
1883 size_t pos = pos1 < pos2 ? pos1 : pos2;
1884
1885 mapOfParams[it->first] = endLine.substr(0, pos);
1886 endLine = endLine.substr(pos + 1);
1887 }
1888 }
1889 }
1890 }
1891
1892 return mapOfParams;
1893}
1894
1943void vpMbTracker::loadCAOModel(const std::string &modelFile, std::vector<std::string> &vectorOfModelFilename,
1944 int &startIdFace, bool verbose, bool parent, const vpHomogeneousMatrix &od_M_o)
1945{
1946 const unsigned int maxDataCAO = 100000; // arbitrary value
1947
1948 std::ifstream fileId;
1949 fileId.exceptions(std::ifstream::failbit | std::ifstream::eofbit);
1950 fileId.open(modelFile.c_str(), std::ifstream::in);
1951 if (fileId.fail()) {
1952 std::cout << "Cannot open CAO model file: " << modelFile << std::endl;
1953 throw vpException(vpException::ioError, "Cannot open model-based tracker CAO model file %s", modelFile.c_str());
1954 }
1955
1956 if (verbose) {
1957 std::cout << "Model file : " << modelFile << std::endl;
1958 }
1959 vectorOfModelFilename.push_back(modelFile);
1960
1961 try {
1962 char c;
1963 // Extraction of the version (remove empty line and commented ones (a commented line begin with the #)).
1965
1967 int caoVersion;
1968 fileId.get(c);
1969 if (c == 'V') {
1970 fileId >> caoVersion;
1971 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
1972 }
1973 else {
1974 fileId.close();
1975 std::cout << "in vpMbTracker::loadCAOModel() -> Bad parameter header file : use V0, V1, ...";
1976 throw vpException(vpException::badValue, "in vpMbTracker::loadCAOModel() -> Bad parameter "
1977 "header file : use V0, V1, ...");
1978 }
1979
1981
1983 std::string line;
1984 const std::string prefix_load = "load";
1985
1986 fileId.get(c);
1987 fileId.unget();
1988 bool header = false;
1989 while ((c == 'l') || (c == 'L')) {
1990 getline(fileId, line);
1991
1992 // Test if "load" keyword is found
1993 if (!line.compare(0, prefix_load.size(), prefix_load)) {
1994 // remove "load("
1995 std::string paramsStr = line.substr(5);
1996 // get parameters inside load()
1997 paramsStr = paramsStr.substr(0, paramsStr.find_first_of(")"));
1998 // split by comma
1999 std::vector<std::string> params = vpIoTools::splitChain(paramsStr, ",");
2000 // remove whitespaces
2001 for (size_t i = 0; i < params.size(); i++) {
2002 params[i] = vpIoTools::trim(params[i]);
2003 }
2004
2005 if (!params.empty()) {
2006 // Get the loaded model pathname
2007 std::string headerPathRead = params[0];
2008 headerPathRead = headerPathRead.substr(1);
2009 headerPathRead = headerPathRead.substr(0, headerPathRead.find_first_of("\""));
2010
2011 std::string headerPath = headerPathRead;
2012 if (!vpIoTools::isAbsolutePathname(headerPathRead)) {
2013 std::string parentDirectory = vpIoTools::getParent(modelFile);
2014 headerPath = vpIoTools::createFilePath(parentDirectory, headerPathRead);
2015 }
2016
2017 // Normalize path
2018 headerPath = vpIoTools::path(headerPath);
2019
2020 // Get real path
2021 headerPath = vpIoTools::getAbsolutePathname(headerPath);
2022
2023 vpHomogeneousMatrix o_M_o_from_cao;
2026 for (size_t i = 1; i < params.size(); i++) {
2027 std::string param = params[i];
2028 {
2029 const std::string prefix = "t=[";
2030 if (!param.compare(0, prefix.size(), prefix)) {
2031 param = param.substr(prefix.size());
2032 param = param.substr(0, param.find_first_of("]"));
2033
2034 std::vector<std::string> values = vpIoTools::splitChain(param, ";");
2035 if (values.size() == 3) {
2036 t[0] = atof(values[0].c_str());
2037 t[1] = atof(values[1].c_str());
2038 t[2] = atof(values[2].c_str());
2039 }
2040 }
2041 }
2042 {
2043 const std::string prefix = "tu=[";
2044 if (!param.compare(0, prefix.size(), prefix)) {
2045 param = param.substr(prefix.size());
2046 param = param.substr(0, param.find_first_of("]"));
2047
2048 std::vector<std::string> values = vpIoTools::splitChain(param, ";");
2049 if (values.size() == 3) {
2050 vpThetaUVector tu;
2051 for (size_t j = 0; j < values.size(); j++) {
2052 std::string value = values[j];
2053 bool radian = true;
2054 size_t unitPos = value.find("deg");
2055 if (unitPos != std::string::npos) {
2056 value = value.substr(0, unitPos);
2057 radian = false;
2058 }
2059
2060 unitPos = value.find("rad");
2061 if (unitPos != std::string::npos) {
2062 value = value.substr(0, unitPos);
2063 }
2064 tu[static_cast<unsigned int>(j)] = !radian ? vpMath::rad(atof(value.c_str())) : atof(value.c_str());
2065 R.buildFrom(tu);
2066 }
2067 }
2068 }
2069 }
2070 {
2071 const std::string prefix = "R=[";
2072 if (!param.compare(0, prefix.size(), prefix)) {
2073 param = param.substr(prefix.size());
2074 param = param.substr(0, param.find_first_of("]"));
2075
2076 std::vector<std::string> values = vpIoTools::splitChain(param, ";");
2077 if (values.size() == 9) {
2078 R[0][0] = atof(values[0].c_str());
2079 R[0][1] = atof(values[1].c_str());
2080 R[0][2] = atof(values[2].c_str());
2081 R[1][0] = atof(values[3].c_str());
2082 R[1][1] = atof(values[4].c_str());
2083 R[1][2] = atof(values[5].c_str());
2084 R[2][0] = atof(values[6].c_str());
2085 R[2][1] = atof(values[7].c_str());
2086 R[2][2] = atof(values[8].c_str());
2087 }
2088 }
2089 }
2090 }
2091 o_M_o_from_cao.buildFrom(t, R);
2092 bool cyclic = false;
2093 for (std::vector<std::string>::const_iterator it = vectorOfModelFilename.begin();
2094 it != vectorOfModelFilename.end() && !cyclic; ++it) {
2095 if (headerPath == *it) {
2096 cyclic = true;
2097 }
2098 }
2099
2100 if (!cyclic) {
2101 if (vpIoTools::checkFilename(headerPath)) {
2102 header = true;
2103 loadCAOModel(headerPath, vectorOfModelFilename, startIdFace, verbose, false, od_M_o * o_M_o_from_cao);
2104 }
2105 else {
2106 fileId.close();
2107 throw vpException(vpException::ioError, "file cannot be open");
2108 }
2109 }
2110 else {
2111 std::cout << "WARNING Cyclic dependency detected with file " << headerPath << " declared in " << modelFile
2112 << std::endl;
2113 }
2114 }
2115 }
2116 try {
2118 if (fileId.eof()) {
2119 return;
2120 }
2121 }
2122 catch (...) {
2123 if (fileId.eof()) {
2124 return;
2125 }
2126 }
2127 fileId.get(c);
2128 fileId.unget();
2129 }
2130
2132 unsigned int caoNbrPoint;
2133 fileId >> caoNbrPoint;
2134 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
2135
2136 nbPoints += caoNbrPoint;
2137 if (verbose || (parent && !header)) {
2138#if defined(VISP_HAVE_THREADS)
2139 std::lock_guard<std::mutex> lock(g_mutex_cout);
2140#endif
2141 std::cout << "> " << caoNbrPoint << " points" << std::endl;
2142 }
2143
2144 if (caoNbrPoint > maxDataCAO) {
2145 fileId.close();
2146 throw vpException(vpException::badValue, "Exceed the max number of points in the CAO model.");
2147 }
2148
2149 if (caoNbrPoint == 0 && !header) {
2150 fileId.close();
2151 throw vpException(vpException::badValue, "in vpMbTracker::loadCAOModel() -> no points are defined");
2152 }
2153 std::vector<vpPoint> caoPoints(caoNbrPoint);
2154
2155 for (unsigned int k = 0; k < caoNbrPoint; k++) {
2157
2158 vpColVector pt_3d(4, 1.0);
2159 fileId >> pt_3d[0];
2160 fileId >> pt_3d[1];
2161 fileId >> pt_3d[2];
2162
2163 if (caoVersion == 2) {
2164 // glob values (not used in MBT but for matching)
2165 int i, j; // image coordinate (used for matching)
2166 fileId >> i;
2167 fileId >> j;
2168 }
2169
2170 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
2171
2172 vpColVector pt_3d_tf = od_M_o * pt_3d;
2173 caoPoints[k].setWorldCoordinates(pt_3d_tf[0], pt_3d_tf[1], pt_3d_tf[2]);
2174 }
2175
2177
2179 // Store in a map the potential segments to add
2180 std::map<std::pair<unsigned int, unsigned int>, SegmentInfo> segmentTemporaryMap;
2181 unsigned int caoNbrLine;
2182 fileId >> caoNbrLine;
2183 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
2184
2185 nbLines += caoNbrLine;
2186 std::vector<unsigned int> caoLinePoints;
2187 if (verbose || (parent && !header)) {
2188#if defined(VISP_HAVE_THREADS)
2189 std::lock_guard<std::mutex> lock(g_mutex_cout);
2190#endif
2191 std::cout << "> " << caoNbrLine << " lines" << std::endl;
2192 }
2193
2194 if (caoNbrLine > maxDataCAO) {
2195 fileId.close();
2196 throw vpException(vpException::badValue, "Exceed the max number of lines in the CAO model.");
2197 }
2198
2199 if (caoNbrLine > 0)
2200 caoLinePoints.resize(2 * caoNbrLine);
2201
2202 unsigned int index1, index2;
2203 // Initialization of idFace with startIdFace for dealing with recursive
2204 // load in header
2205 int idFace = startIdFace;
2206
2207 for (unsigned int k = 0; k < caoNbrLine; k++) {
2209
2210 fileId >> index1;
2211 fileId >> index2;
2212
2214 // Get the end of the line
2215 std::string endLine = "";
2216 if (safeGetline(fileId, endLine).good()) {
2217 std::map<std::string, std::string> mapOfParams = parseParameters(endLine);
2218
2219 std::string segmentName = "";
2220 double minLineLengthThresh = !applyLodSettingInConfig ? minLineLengthThresholdGeneral : 50.0;
2221 bool useLod = !applyLodSettingInConfig ? useLodGeneral : false;
2222 if (mapOfParams.find("name") != mapOfParams.end()) {
2223 segmentName = mapOfParams["name"];
2224 }
2225 if (mapOfParams.find("minLineLengthThreshold") != mapOfParams.end()) {
2226 minLineLengthThresh = std::atof(mapOfParams["minLineLengthThreshold"].c_str());
2227 }
2228 if (mapOfParams.find("useLod") != mapOfParams.end()) {
2229 useLod = vpIoTools::parseBoolean(mapOfParams["useLod"]);
2230 }
2231
2232 SegmentInfo segmentInfo;
2233 segmentInfo.name = segmentName;
2234 segmentInfo.useLod = useLod;
2235 segmentInfo.minLineLengthThresh = minLineLengthThresh;
2236
2237 caoLinePoints[2 * k] = index1;
2238 caoLinePoints[2 * k + 1] = index2;
2239
2240 if (index1 < caoNbrPoint && index2 < caoNbrPoint) {
2241 std::vector<vpPoint> extremities;
2242 extremities.push_back(caoPoints[index1]);
2243 extremities.push_back(caoPoints[index2]);
2244 segmentInfo.extremities = extremities;
2245
2246 std::pair<unsigned int, unsigned int> key(index1, index2);
2247
2248 segmentTemporaryMap[key] = segmentInfo;
2249 }
2250 else {
2251 vpTRACE(" line %d has wrong coordinates.", k);
2252 }
2253 }
2254 }
2255
2257
2259 /* Load polygon from the lines extracted earlier (the first point of the
2260 * line is used)*/
2261 // Store in a vector the indexes of the segments added in the face segment
2262 // case
2263 std::vector<std::pair<unsigned int, unsigned int> > faceSegmentKeyVector;
2264 unsigned int caoNbrPolygonLine;
2265 fileId >> caoNbrPolygonLine;
2266 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
2267
2268 nbPolygonLines += caoNbrPolygonLine;
2269 if (verbose || (parent && !header)) {
2270#if defined(VISP_HAVE_THREADS)
2271 std::lock_guard<std::mutex> lock(g_mutex_cout);
2272#endif
2273 std::cout << "> " << caoNbrPolygonLine << " polygon lines" << std::endl;
2274 }
2275
2276 if (caoNbrPolygonLine > maxDataCAO) {
2277 fileId.close();
2278 throw vpException(vpException::badValue, "Exceed the max number of polygon lines.");
2279 }
2280
2281 unsigned int index;
2282 for (unsigned int k = 0; k < caoNbrPolygonLine; k++) {
2284
2285 unsigned int nbLinePol;
2286 fileId >> nbLinePol;
2287 std::vector<vpPoint> corners;
2288 if (nbLinePol > maxDataCAO) {
2289 fileId.close();
2290 throw vpException(vpException::badValue, "Exceed the max number of lines.");
2291 }
2292
2293 for (unsigned int n = 0; n < nbLinePol; n++) {
2294 fileId >> index;
2295
2296 if (index >= caoNbrLine) {
2297 fileId.close();
2298 throw vpException(vpException::badValue, "Exceed the max number of lines.");
2299 }
2300 corners.push_back(caoPoints[caoLinePoints[2 * index]]);
2301 corners.push_back(caoPoints[caoLinePoints[2 * index + 1]]);
2302
2303 std::pair<unsigned int, unsigned int> key(caoLinePoints[2 * index], caoLinePoints[2 * index + 1]);
2304 faceSegmentKeyVector.push_back(key);
2305 }
2306
2308 // Get the end of the line
2309 std::string endLine = "";
2310 if (safeGetline(fileId, endLine).good()) {
2311 std::map<std::string, std::string> mapOfParams = parseParameters(endLine);
2312
2313 std::string polygonName = "";
2314 bool useLod = !applyLodSettingInConfig ? useLodGeneral : false;
2315 double minPolygonAreaThreshold = !applyLodSettingInConfig ? minPolygonAreaThresholdGeneral : 2500.0;
2316 if (mapOfParams.find("name") != mapOfParams.end()) {
2317 polygonName = mapOfParams["name"];
2318 }
2319 if (mapOfParams.find("minPolygonAreaThreshold") != mapOfParams.end()) {
2320 minPolygonAreaThreshold = std::atof(mapOfParams["minPolygonAreaThreshold"].c_str());
2321 }
2322 if (mapOfParams.find("useLod") != mapOfParams.end()) {
2323 useLod = vpIoTools::parseBoolean(mapOfParams["useLod"]);
2324 }
2325
2326 addPolygon(corners, idFace, polygonName, useLod, minPolygonAreaThreshold, minLineLengthThresholdGeneral);
2327 initFaceFromLines(*(faces.getPolygon().back())); // Init from the last polygon that was added
2328
2329 addProjectionErrorPolygon(corners, idFace++, polygonName, useLod, minPolygonAreaThreshold,
2332 }
2333 }
2334
2335 // Add the segments which were not already added in the face segment case
2336 for (std::map<std::pair<unsigned int, unsigned int>, SegmentInfo>::const_iterator it = segmentTemporaryMap.begin();
2337 it != segmentTemporaryMap.end(); ++it) {
2338 if (std::find(faceSegmentKeyVector.begin(), faceSegmentKeyVector.end(), it->first) ==
2339 faceSegmentKeyVector.end()) {
2340 addPolygon(it->second.extremities, idFace, it->second.name, it->second.useLod, minPolygonAreaThresholdGeneral,
2341 it->second.minLineLengthThresh);
2342 initFaceFromCorners(*(faces.getPolygon().back())); // Init from the last polygon that was added
2343
2344 addProjectionErrorPolygon(it->second.extremities, idFace++, it->second.name, it->second.useLod,
2345 minPolygonAreaThresholdGeneral, it->second.minLineLengthThresh);
2347 }
2348 }
2349
2351
2353 /* Extract the polygon using the point coordinates (top of the file) */
2354 unsigned int caoNbrPolygonPoint;
2355 fileId >> caoNbrPolygonPoint;
2356 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
2357
2358 nbPolygonPoints += caoNbrPolygonPoint;
2359 if (verbose || (parent && !header)) {
2360#if defined(VISP_HAVE_THREADS)
2361 std::lock_guard<std::mutex> lock(g_mutex_cout);
2362#endif
2363 std::cout << "> " << caoNbrPolygonPoint << " polygon points" << std::endl;
2364 }
2365
2366 if (caoNbrPolygonPoint > maxDataCAO) {
2367 fileId.close();
2368 throw vpException(vpException::badValue, "Exceed the max number of polygon point.");
2369 }
2370
2371 for (unsigned int k = 0; k < caoNbrPolygonPoint; k++) {
2373
2374 unsigned int nbPointPol;
2375 fileId >> nbPointPol;
2376 if (nbPointPol > maxDataCAO) {
2377 fileId.close();
2378 throw vpException(vpException::badValue, "Exceed the max number of points.");
2379 }
2380 std::vector<vpPoint> corners;
2381 for (unsigned int n = 0; n < nbPointPol; n++) {
2382 fileId >> index;
2383 if (index > caoNbrPoint - 1) {
2384 fileId.close();
2385 throw vpException(vpException::badValue, "Exceed the max number of points.");
2386 }
2387 corners.push_back(caoPoints[index]);
2388 }
2389
2391 // Get the end of the line
2392 std::string endLine = "";
2393 if (safeGetline(fileId, endLine).good()) {
2394 std::map<std::string, std::string> mapOfParams = parseParameters(endLine);
2395
2396 std::string polygonName = "";
2397 bool useLod = !applyLodSettingInConfig ? useLodGeneral : false;
2398 double minPolygonAreaThreshold = !applyLodSettingInConfig ? minPolygonAreaThresholdGeneral : 2500.0;
2399 if (mapOfParams.find("name") != mapOfParams.end()) {
2400 polygonName = mapOfParams["name"];
2401 }
2402 if (mapOfParams.find("minPolygonAreaThreshold") != mapOfParams.end()) {
2403 minPolygonAreaThreshold = std::atof(mapOfParams["minPolygonAreaThreshold"].c_str());
2404 }
2405 if (mapOfParams.find("useLod") != mapOfParams.end()) {
2406 useLod = vpIoTools::parseBoolean(mapOfParams["useLod"]);
2407 }
2408
2409 addPolygon(corners, idFace, polygonName, useLod, minPolygonAreaThreshold, minLineLengthThresholdGeneral);
2410 initFaceFromCorners(*(faces.getPolygon().back())); // Init from the last polygon that was added
2411
2412 addProjectionErrorPolygon(corners, idFace++, polygonName, useLod, minPolygonAreaThreshold,
2415 }
2416 }
2417
2419 unsigned int caoNbCylinder;
2420 try {
2422
2423 if (fileId.eof()) { // check if not at the end of the file (for old style files)
2424 return;
2425 }
2426
2427 /* Extract the cylinders */
2428 fileId >> caoNbCylinder;
2429 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
2430
2431 nbCylinders += caoNbCylinder;
2432 if (verbose || (parent && !header)) {
2433#if defined(VISP_HAVE_THREADS)
2434 std::lock_guard<std::mutex> lock(g_mutex_cout);
2435#endif
2436 std::cout << "> " << caoNbCylinder << " cylinders" << std::endl;
2437 }
2438
2439 if (caoNbCylinder > maxDataCAO) {
2440 fileId.close();
2441 throw vpException(vpException::badValue, "Exceed the max number of cylinders.");
2442 }
2443
2444 for (unsigned int k = 0; k < caoNbCylinder; ++k) {
2446
2447 double radius;
2448 unsigned int indexP1, indexP2;
2449 fileId >> indexP1;
2450 fileId >> indexP2;
2451 fileId >> radius;
2452
2454 // Get the end of the line
2455 std::string endLine = "";
2456 if (safeGetline(fileId, endLine).good()) {
2457 std::map<std::string, std::string> mapOfParams = parseParameters(endLine);
2458
2459 std::string polygonName = "";
2460 bool useLod = !applyLodSettingInConfig ? useLodGeneral : false;
2461 double minLineLengthThreshold = !applyLodSettingInConfig ? minLineLengthThresholdGeneral : 50.0;
2462 if (mapOfParams.find("name") != mapOfParams.end()) {
2463 polygonName = mapOfParams["name"];
2464 }
2465 if (mapOfParams.find("minLineLengthThreshold") != mapOfParams.end()) {
2466 minLineLengthThreshold = std::atof(mapOfParams["minLineLengthThreshold"].c_str());
2467 }
2468 if (mapOfParams.find("useLod") != mapOfParams.end()) {
2469 useLod = vpIoTools::parseBoolean(mapOfParams["useLod"]);
2470 }
2471
2472 int idRevolutionAxis = idFace;
2473 addPolygon(caoPoints[indexP1], caoPoints[indexP2], idFace, polygonName, useLod, minLineLengthThreshold);
2474
2475 addProjectionErrorPolygon(caoPoints[indexP1], caoPoints[indexP2], idFace++, polygonName, useLod,
2476 minLineLengthThreshold);
2477
2478 std::vector<std::vector<vpPoint> > listFaces;
2479 createCylinderBBox(caoPoints[indexP1], caoPoints[indexP2], radius, listFaces);
2480 addPolygon(listFaces, idFace, polygonName, useLod, minLineLengthThreshold);
2481
2482 initCylinder(caoPoints[indexP1], caoPoints[indexP2], radius, idRevolutionAxis, polygonName);
2483
2484 addProjectionErrorPolygon(listFaces, idFace, polygonName, useLod, minLineLengthThreshold);
2485 initProjectionErrorCylinder(caoPoints[indexP1], caoPoints[indexP2], radius, idRevolutionAxis, polygonName);
2486
2487 idFace += 4;
2488 }
2489 }
2490
2491 }
2492 catch (const std::exception &e) {
2493 std::cerr << "Cannot get the number of cylinders. Defaulting to zero." << std::endl;
2494 std::cerr << "Exception: " << e.what() << std::endl;
2495 caoNbCylinder = 0;
2496 }
2497
2499 unsigned int caoNbCircle;
2500 try {
2502
2503 if (fileId.eof()) { // check if not at the end of the file (for old
2504 // style files)
2505 return;
2506 }
2507
2508 // To handle CAO model file without no new line at the end, we check if the first char is zero or not
2509 // Otherwise "fileId >> caoNbCircle;" gives:
2510 // "Cannot get the number of circles. Defaulting to zero."
2511 // "Exception: basic_ios::clear: iostream error"
2512 char c_circle;
2513 fileId.get(c_circle);
2514 int nb_circles = c_circle - '0';
2515 if (nb_circles > 0) {
2516 fileId.unget();
2517
2518 /* Extract the circles */
2519 fileId >> caoNbCircle;
2520 fileId.ignore(std::numeric_limits<std::streamsize>::max(), fileId.widen('\n')); // skip the rest of the line
2521
2522 nbCircles += caoNbCircle;
2523 if (verbose || (parent && !header)) {
2524#if defined(VISP_HAVE_THREADS)
2525 std::lock_guard<std::mutex> lock(g_mutex_cout);
2526#endif
2527 std::cout << "> " << caoNbCircle << " circles" << std::endl;
2528 }
2529
2530 if (caoNbCircle > maxDataCAO) {
2531 fileId.close();
2532 throw vpException(vpException::badValue, "Exceed the max number of cicles.");
2533 }
2534
2535 for (unsigned int k = 0; k < caoNbCircle; ++k) {
2537
2538 double radius;
2539 unsigned int indexP1, indexP2, indexP3;
2540 fileId >> radius;
2541 fileId >> indexP1;
2542 fileId >> indexP2;
2543 fileId >> indexP3;
2544
2546 // Get the end of the line
2547 std::string endLine = "";
2548 if (safeGetline(fileId, endLine).good()) {
2549 std::map<std::string, std::string> mapOfParams = parseParameters(endLine);
2550
2551 std::string polygonName = "";
2552 bool useLod = !applyLodSettingInConfig ? useLodGeneral : false;
2553 double minPolygonAreaThreshold = !applyLodSettingInConfig ? minPolygonAreaThresholdGeneral : 2500.0;
2554 if (mapOfParams.find("name") != mapOfParams.end()) {
2555 polygonName = mapOfParams["name"];
2556 }
2557 if (mapOfParams.find("minPolygonAreaThreshold") != mapOfParams.end()) {
2558 minPolygonAreaThreshold = std::atof(mapOfParams["minPolygonAreaThreshold"].c_str());
2559 }
2560 if (mapOfParams.find("useLod") != mapOfParams.end()) {
2561 useLod = vpIoTools::parseBoolean(mapOfParams["useLod"]);
2562 }
2563
2564 addPolygon(caoPoints[indexP1], caoPoints[indexP2], caoPoints[indexP3], radius, idFace, polygonName, useLod,
2565 minPolygonAreaThreshold);
2566
2567 initCircle(caoPoints[indexP1], caoPoints[indexP2], caoPoints[indexP3], radius, idFace, polygonName);
2568
2569 addProjectionErrorPolygon(caoPoints[indexP1], caoPoints[indexP2], caoPoints[indexP3], radius, idFace,
2570 polygonName, useLod, minPolygonAreaThreshold);
2571 initProjectionErrorCircle(caoPoints[indexP1], caoPoints[indexP2], caoPoints[indexP3], radius, idFace++,
2572 polygonName);
2573 }
2574 }
2575 }
2576 }
2577 catch (const std::exception &e) {
2578 std::cerr << "Cannot get the number of circles. Defaulting to zero." << std::endl;
2579 std::cerr << "Exception: " << e.what() << std::endl;
2580 caoNbCircle = 0;
2581 }
2582
2583 startIdFace = idFace;
2584
2585 if (header && parent) {
2586 if (verbose) {
2587#if defined(VISP_HAVE_THREADS)
2588 std::lock_guard<std::mutex> lock(g_mutex_cout);
2589#endif
2590 std::cout << "Global information for " << vpIoTools::getName(modelFile) << " :" << std::endl;
2591 std::cout << "Total nb of points : " << nbPoints << std::endl;
2592 std::cout << "Total nb of lines : " << nbLines << std::endl;
2593 std::cout << "Total nb of polygon lines : " << nbPolygonLines << std::endl;
2594 std::cout << "Total nb of polygon points : " << nbPolygonPoints << std::endl;
2595 std::cout << "Total nb of cylinders : " << nbCylinders << std::endl;
2596 std::cout << "Total nb of circles : " << nbCircles << std::endl;
2597 }
2598 else {
2599#if defined(VISP_HAVE_THREADS)
2600 std::lock_guard<std::mutex> lock(g_mutex_cout);
2601#endif
2602 std::cout << "> " << nbPoints << " points" << std::endl;
2603 std::cout << "> " << nbLines << " lines" << std::endl;
2604 std::cout << "> " << nbPolygonLines << " polygon lines" << std::endl;
2605 std::cout << "> " << nbPolygonPoints << " polygon points" << std::endl;
2606 std::cout << "> " << nbCylinders << " cylinders" << std::endl;
2607 std::cout << "> " << nbCircles << " circles" << std::endl;
2608 }
2609 }
2610
2611 // Go up: remove current model
2612 vectorOfModelFilename.pop_back();
2613
2614 fileId.close();
2615 }
2616 catch (const std::exception &e) {
2617 fileId.close();
2618 std::cerr << "Cannot read line!" << std::endl;
2619 std::cerr << "Exception: " << e.what() << std::endl;
2620 throw vpException(vpException::ioError, "cannot read line");
2621 }
2622}
2623
2624#ifdef VISP_HAVE_COIN3D
2632void vpMbTracker::extractGroup(SoVRMLGroup *sceneGraphVRML2, vpHomogeneousMatrix &transform, int &idFace)
2633{
2634 vpHomogeneousMatrix transformCur;
2635 SoVRMLTransform *sceneGraphVRML2Trasnform = dynamic_cast<SoVRMLTransform *>(sceneGraphVRML2);
2636 if (sceneGraphVRML2Trasnform) {
2637 float rx, ry, rz, rw;
2638 sceneGraphVRML2Trasnform->rotation.getValue().getValue(rx, ry, rz, rw);
2639 vpRotationMatrix rotMat(vpQuaternionVector(rx, ry, rz, rw));
2640 // std::cout << "Rotation: " << rx << " " << ry << " " << rz << " " <<
2641 // rw << std::endl;
2642
2643 float tx, ty, tz;
2644 tx = sceneGraphVRML2Trasnform->translation.getValue()[0];
2645 ty = sceneGraphVRML2Trasnform->translation.getValue()[1];
2646 tz = sceneGraphVRML2Trasnform->translation.getValue()[2];
2647 vpTranslationVector transVec(tx, ty, tz);
2648 // std::cout << "Translation: " << tx << " " << ty << " " << tz <<
2649 // std::endl;
2650
2651 float sx, sy, sz;
2652 sx = sceneGraphVRML2Trasnform->scale.getValue()[0];
2653 sy = sceneGraphVRML2Trasnform->scale.getValue()[1];
2654 sz = sceneGraphVRML2Trasnform->scale.getValue()[2];
2655 // std::cout << "Scale: " << sx << " " << sy << " " << sz <<
2656 // std::endl;
2657
2658 for (unsigned int i = 0; i < 3; i++)
2659 rotMat[0][i] *= sx;
2660 for (unsigned int i = 0; i < 3; i++)
2661 rotMat[1][i] *= sy;
2662 for (unsigned int i = 0; i < 3; i++)
2663 rotMat[2][i] *= sz;
2664
2665 transformCur = vpHomogeneousMatrix(transVec, rotMat);
2666 transform = transform * transformCur;
2667 }
2668
2669 int nbShapes = sceneGraphVRML2->getNumChildren();
2670 // std::cout << sceneGraphVRML2->getTypeId().getName().getString() <<
2671 // std::endl; std::cout << "Nb object in VRML : " << nbShapes <<
2672 // std::endl;
2673
2674 SoNode *child;
2675
2676 for (int i = 0; i < nbShapes; i++) {
2677 vpHomogeneousMatrix transform_recursive(transform);
2678 child = sceneGraphVRML2->getChild(i);
2679
2680 if (child->getTypeId() == SoVRMLGroup::getClassTypeId()) {
2681 extractGroup((SoVRMLGroup *)child, transform_recursive, idFace);
2682 }
2683
2684 if (child->getTypeId() == SoVRMLTransform::getClassTypeId()) {
2685 extractGroup((SoVRMLTransform *)child, transform_recursive, idFace);
2686 }
2687
2688 if (child->getTypeId() == SoVRMLShape::getClassTypeId()) {
2689 SoChildList *child2list = child->getChildren();
2690 std::string name = child->getName().getString();
2691
2692 for (int j = 0; j < child2list->getLength(); j++) {
2693 if (((SoNode *)child2list->get(j))->getTypeId() == SoVRMLIndexedFaceSet::getClassTypeId()) {
2694 SoVRMLIndexedFaceSet *face_set;
2695 face_set = (SoVRMLIndexedFaceSet *)child2list->get(j);
2696 if (!strncmp(face_set->getName().getString(), "cyl", 3)) {
2697 extractCylinders(face_set, transform, idFace, name);
2698 }
2699 else {
2700 extractFaces(face_set, transform, idFace, name);
2701 }
2702 }
2703 if (((SoNode *)child2list->get(j))->getTypeId() == SoVRMLIndexedLineSet::getClassTypeId()) {
2704 SoVRMLIndexedLineSet *line_set;
2705 line_set = (SoVRMLIndexedLineSet *)child2list->get(j);
2706 extractLines(line_set, idFace, name);
2707 }
2708 }
2709 }
2710 }
2711}
2712
2722void vpMbTracker::extractFaces(SoVRMLIndexedFaceSet *face_set, vpHomogeneousMatrix &transform, int &idFace,
2723 const std::string &polygonName)
2724{
2725 std::vector<vpPoint> corners;
2726
2727 // SoMFInt32 indexList = _face_set->coordIndex;
2728 // int indexListSize = indexList.getNum();
2729 int indexListSize = face_set->coordIndex.getNum();
2730
2731 vpColVector pointTransformed(4);
2732 vpPoint pt;
2733 SoVRMLCoordinate *coord;
2734
2735 for (int i = 0; i < indexListSize; i++) {
2736 if (face_set->coordIndex[i] == -1) {
2737 if (corners.size() > 1) {
2738 addPolygon(corners, idFace, polygonName);
2739 initFaceFromCorners(*(faces.getPolygon().back())); // Init from the last polygon that was added
2740
2741 addProjectionErrorPolygon(corners, idFace++, polygonName);
2743 corners.resize(0);
2744 }
2745 }
2746 else {
2747 coord = (SoVRMLCoordinate *)(face_set->coord.getValue());
2748 int index = face_set->coordIndex[i];
2749 pointTransformed[0] = coord->point[index].getValue()[0];
2750 pointTransformed[1] = coord->point[index].getValue()[1];
2751 pointTransformed[2] = coord->point[index].getValue()[2];
2752 pointTransformed[3] = 1.0;
2753
2754 pointTransformed = transform * pointTransformed;
2755
2756 pt.setWorldCoordinates(pointTransformed[0], pointTransformed[1], pointTransformed[2]);
2757 corners.push_back(pt);
2758 }
2759 }
2760}
2761
2776void vpMbTracker::extractCylinders(SoVRMLIndexedFaceSet *face_set, vpHomogeneousMatrix &transform, int &idFace,
2777 const std::string &polygonName)
2778{
2779 std::vector<vpPoint> corners_c1, corners_c2; // points belonging to the
2780 // first circle and to the
2781 // second one.
2782 SoVRMLCoordinate *coords = (SoVRMLCoordinate *)face_set->coord.getValue();
2783
2784 unsigned int indexListSize = static_cast<unsigned int>(coords->point.getNum());
2785
2786 if (indexListSize % 2 == 1) {
2787 std::cout << "Not an even number of points when extracting a cylinder." << std::endl;
2788 throw vpException(vpException::dimensionError, "Not an even number of points when extracting a cylinder.");
2789 }
2790 corners_c1.resize(indexListSize / 2);
2791 corners_c2.resize(indexListSize / 2);
2792 vpColVector pointTransformed(4);
2793 vpPoint pt;
2794
2795 // extract all points and fill the two sets.
2796
2797 for (int i = 0; i < coords->point.getNum(); ++i) {
2798 pointTransformed[0] = coords->point[i].getValue()[0];
2799 pointTransformed[1] = coords->point[i].getValue()[1];
2800 pointTransformed[2] = coords->point[i].getValue()[2];
2801 pointTransformed[3] = 1.0;
2802
2803 pointTransformed = transform * pointTransformed;
2804
2805 pt.setWorldCoordinates(pointTransformed[0], pointTransformed[1], pointTransformed[2]);
2806
2807 if (i < static_cast<int>(corners_c1.size())) {
2808 corners_c1[static_cast<unsigned int>(i)] = pt;
2809 }
2810 else {
2811 corners_c2[static_cast<unsigned int>(i) - corners_c1.size()] = pt;
2812 }
2813 }
2814
2815 vpPoint p1 = getGravityCenter(corners_c1);
2816 vpPoint p2 = getGravityCenter(corners_c2);
2817
2818 vpColVector dist(3);
2819 dist[0] = p1.get_oX() - corners_c1[0].get_oX();
2820 dist[1] = p1.get_oY() - corners_c1[0].get_oY();
2821 dist[2] = p1.get_oZ() - corners_c1[0].get_oZ();
2822 double radius_c1 = sqrt(dist.sumSquare());
2823 dist[0] = p2.get_oX() - corners_c2[0].get_oX();
2824 dist[1] = p2.get_oY() - corners_c2[0].get_oY();
2825 dist[2] = p2.get_oZ() - corners_c2[0].get_oZ();
2826 double radius_c2 = sqrt(dist.sumSquare());
2827
2828 if (std::fabs(radius_c1 - radius_c2) >
2829 (std::numeric_limits<double>::epsilon() * vpMath::maximum(radius_c1, radius_c2))) {
2830 std::cout << "Radius from the two circles of the cylinders are different." << std::endl;
2831 throw vpException(vpException::badValue, "Radius from the two circles of the cylinders are different.");
2832 }
2833
2834 // addPolygon(p1, p2, idFace, polygonName);
2835 // initCylinder(p1, p2, radius_c1, idFace++);
2836
2837 int idRevolutionAxis = idFace;
2838 addPolygon(p1, p2, idFace, polygonName);
2839
2840 addProjectionErrorPolygon(p1, p2, idFace++, polygonName);
2841
2842 std::vector<std::vector<vpPoint> > listFaces;
2843 createCylinderBBox(p1, p2, radius_c1, listFaces);
2844 addPolygon(listFaces, idFace, polygonName);
2845
2846 initCylinder(p1, p2, radius_c1, idRevolutionAxis, polygonName);
2847
2848 addProjectionErrorPolygon(listFaces, idFace, polygonName);
2849 initProjectionErrorCylinder(p1, p2, radius_c1, idRevolutionAxis, polygonName);
2850
2851 idFace += 4;
2852}
2853
2862void vpMbTracker::extractLines(SoVRMLIndexedLineSet *line_set, int &idFace, const std::string &polygonName)
2863{
2864 std::vector<vpPoint> corners;
2865 corners.resize(0);
2866
2867 int indexListSize = line_set->coordIndex.getNum();
2868
2869 SbVec3f point(0, 0, 0);
2870 vpPoint pt;
2871 SoVRMLCoordinate *coord;
2872
2873 for (int i = 0; i < indexListSize; i++) {
2874 if (line_set->coordIndex[i] == -1) {
2875 if (corners.size() > 1) {
2876 addPolygon(corners, idFace, polygonName);
2877 initFaceFromCorners(*(faces.getPolygon().back())); // Init from the last polygon that was added
2878
2879 addProjectionErrorPolygon(corners, idFace++, polygonName);
2881 corners.resize(0);
2882 }
2883 }
2884 else {
2885 coord = (SoVRMLCoordinate *)(line_set->coord.getValue());
2886 int index = line_set->coordIndex[i];
2887 point[0] = coord->point[index].getValue()[0];
2888 point[1] = coord->point[index].getValue()[1];
2889 point[2] = coord->point[index].getValue()[2];
2890
2891 pt.setWorldCoordinates(point[0], point[1], point[2]);
2892 corners.push_back(pt);
2893 }
2894 }
2895}
2896
2897#endif // VISP_HAVE_COIN3D
2898
2908vpPoint vpMbTracker::getGravityCenter(const std::vector<vpPoint> &pts) const
2909{
2910 if (pts.empty()) {
2911 std::cout << "Cannot extract center of gravity of empty set." << std::endl;
2912 throw vpException(vpException::dimensionError, "Cannot extract center of gravity of empty set.");
2913 }
2914 double oX = 0;
2915 double oY = 0;
2916 double oZ = 0;
2917 vpPoint G;
2918
2919 for (unsigned int i = 0; i < pts.size(); ++i) {
2920 oX += pts[i].get_oX();
2921 oY += pts[i].get_oY();
2922 oZ += pts[i].get_oZ();
2923 }
2924
2925 G.setWorldCoordinates(oX / pts.size(), oY / pts.size(), oZ / pts.size());
2926 return G;
2927}
2928
2941std::pair<std::vector<vpPolygon>, std::vector<std::vector<vpPoint> > >
2942vpMbTracker::getPolygonFaces(bool orderPolygons, bool useVisibility, bool clipPolygon)
2943{
2944 // Temporary variable to permit to order polygons by distance
2945 std::vector<vpPolygon> polygonsTmp;
2946 std::vector<std::vector<vpPoint> > roisPtTmp;
2947
2948 // Pair containing the list of vpPolygon and the list of face corners
2949 std::pair<std::vector<vpPolygon>, std::vector<std::vector<vpPoint> > > pairOfPolygonFaces;
2950
2951 for (unsigned int i = 0; i < faces.getPolygon().size(); i++) {
2952 // A face has at least 3 points
2953 if (faces.getPolygon()[i]->nbpt > 2) {
2954 if ((useVisibility && faces.getPolygon()[i]->isvisible) || !useVisibility) {
2955 std::vector<vpImagePoint> roiPts;
2956
2957 if (clipPolygon) {
2958 faces.getPolygon()[i]->getRoiClipped(m_cam, roiPts, m_cMo);
2959 }
2960 else {
2961 roiPts = faces.getPolygon()[i]->getRoi(m_cam, m_cMo);
2962 }
2963
2964 if (roiPts.size() <= 2) {
2965 continue;
2966 }
2967
2968 polygonsTmp.push_back(vpPolygon(roiPts));
2969
2970 std::vector<vpPoint> polyPts;
2971 if (clipPolygon) {
2972 faces.getPolygon()[i]->getPolygonClipped(polyPts);
2973 }
2974 else {
2975 for (unsigned int j = 0; j < faces.getPolygon()[i]->nbpt; j++) {
2976 polyPts.push_back(faces.getPolygon()[i]->p[j]);
2977 }
2978 }
2979 roisPtTmp.push_back(polyPts);
2980 }
2981 }
2982 }
2983
2984 if (orderPolygons) {
2985 // Order polygons by distance (near to far)
2986 std::vector<PolygonFaceInfo> listOfPolygonFaces;
2987 for (unsigned int i = 0; i < polygonsTmp.size(); i++) {
2988 double x_centroid = 0.0, y_centroid = 0.0, z_centroid = 0.0;
2989 for (unsigned int j = 0; j < roisPtTmp[i].size(); j++) {
2990 x_centroid += roisPtTmp[i][j].get_X();
2991 y_centroid += roisPtTmp[i][j].get_Y();
2992 z_centroid += roisPtTmp[i][j].get_Z();
2993 }
2994
2995 x_centroid /= roisPtTmp[i].size();
2996 y_centroid /= roisPtTmp[i].size();
2997 z_centroid /= roisPtTmp[i].size();
2998
2999 double squared_dist = x_centroid * x_centroid + y_centroid * y_centroid + z_centroid * z_centroid;
3000 listOfPolygonFaces.push_back(PolygonFaceInfo(squared_dist, polygonsTmp[i], roisPtTmp[i]));
3001 }
3002
3003 // Sort the list of polygon faces
3004 std::sort(listOfPolygonFaces.begin(), listOfPolygonFaces.end());
3005
3006 polygonsTmp.resize(listOfPolygonFaces.size());
3007 roisPtTmp.resize(listOfPolygonFaces.size());
3008
3009 size_t cpt = 0;
3010 for (std::vector<PolygonFaceInfo>::const_iterator it = listOfPolygonFaces.begin(); it != listOfPolygonFaces.end();
3011 ++it, cpt++) {
3012 polygonsTmp[cpt] = it->polygon;
3013 roisPtTmp[cpt] = it->faceCorners;
3014 }
3015
3016 pairOfPolygonFaces.first = polygonsTmp;
3017 pairOfPolygonFaces.second = roisPtTmp;
3018 }
3019 else {
3020 pairOfPolygonFaces.first = polygonsTmp;
3021 pairOfPolygonFaces.second = roisPtTmp;
3022 }
3023
3024 return pairOfPolygonFaces;
3025}
3026
3035{
3036 useOgre = v;
3037 if (useOgre) {
3038#ifndef VISP_HAVE_OGRE
3039 useOgre = false;
3040 std::cout << "WARNING: ViSP doesn't have Ogre3D, basic visibility test "
3041 "will be used. setOgreVisibilityTest() set to false."
3042 << std::endl;
3043#endif
3044 }
3045}
3046
3053{
3055 vpTRACE("Far clipping value cannot be inferior than near clipping value. "
3056 "Far clipping won't be considered.");
3057 else if (dist < 0)
3058 vpTRACE("Far clipping value cannot be inferior than 0. Far clipping "
3059 "won't be considered.");
3060 else {
3062 distFarClip = dist;
3063 for (unsigned int i = 0; i < faces.size(); i++) {
3064 faces[i]->setFarClippingDistance(distFarClip);
3065 }
3066#ifdef VISP_HAVE_OGRE
3067 faces.getOgreContext()->setFarClippingDistance(distFarClip);
3068#endif
3069 }
3070}
3071
3082void vpMbTracker::setLod(bool useLod, const std::string &name)
3083{
3084 for (unsigned int i = 0; i < faces.size(); i++) {
3085 if (name.empty() || faces[i]->name == name) {
3086 faces[i]->setLod(useLod);
3087 }
3088 }
3089}
3090
3100void vpMbTracker::setMinLineLengthThresh(double minLineLengthThresh, const std::string &name)
3101{
3102 for (unsigned int i = 0; i < faces.size(); i++) {
3103 if (name.empty() || faces[i]->name == name) {
3104 faces[i]->setMinLineLengthThresh(minLineLengthThresh);
3105 }
3106 }
3107}
3108
3117void vpMbTracker::setMinPolygonAreaThresh(double minPolygonAreaThresh, const std::string &name)
3118{
3119 for (unsigned int i = 0; i < faces.size(); i++) {
3120 if (name.empty() || faces[i]->name == name) {
3121 faces[i]->setMinPolygonAreaThresh(minPolygonAreaThresh);
3122 }
3123 }
3124}
3125
3132{
3134 vpTRACE("Near clipping value cannot be superior than far clipping value. "
3135 "Near clipping won't be considered.");
3136 else if (dist < 0)
3137 vpTRACE("Near clipping value cannot be inferior than 0. Near clipping "
3138 "won't be considered.");
3139 else {
3141 distNearClip = dist;
3142 for (unsigned int i = 0; i < faces.size(); i++) {
3143 faces[i]->setNearClippingDistance(distNearClip);
3144 }
3145#ifdef VISP_HAVE_OGRE
3146 faces.getOgreContext()->setNearClippingDistance(distNearClip);
3147#endif
3148 }
3149}
3150
3158void vpMbTracker::setClipping(const unsigned int &flags)
3159{
3160 clippingFlag = flags;
3161 for (unsigned int i = 0; i < faces.size(); i++)
3163}
3164
3165void vpMbTracker::computeCovarianceMatrixVVS(const bool isoJoIdentity, const vpColVector &w_true,
3166 const vpHomogeneousMatrix &cMoPrev, const vpMatrix &L_true,
3167 const vpMatrix &LVJ_true, const vpColVector &error)
3168{
3169 if (computeCovariance) {
3170 vpMatrix D;
3171 D.diag(w_true);
3172
3173 // Note that here the covariance is computed on cMoPrev for time
3174 // computation efficiency
3175 if (isoJoIdentity) {
3176 covarianceMatrix = vpMatrix::computeCovarianceMatrixVVS(cMoPrev, error, L_true, D);
3177 }
3178 else {
3179 covarianceMatrix = vpMatrix::computeCovarianceMatrixVVS(cMoPrev, error, LVJ_true, D);
3180 }
3181 }
3182}
3183
3196void vpMbTracker::computeJTR(const vpMatrix &interaction, const vpColVector &error, vpColVector &JTR) const
3197{
3198 if (interaction.getRows() != error.getRows() || interaction.getCols() != 6) {
3199 throw vpMatrixException(vpMatrixException::incorrectMatrixSizeError, "Incorrect matrices size in computeJTR.");
3200 }
3201
3202 JTR.resize(6, false);
3203#if defined(VISP_HAVE_SIMDLIB)
3204 SimdComputeJtR(interaction.data, interaction.getRows(), error.data, JTR.data);
3205#else
3206 const unsigned int N = interaction.getRows();
3207
3208 for (unsigned int i = 0; i < 6; i += 1) {
3209 double ssum = 0;
3210 for (unsigned int j = 0; j < N; j += 1) {
3211 ssum += interaction[j][i] * error[j];
3212 }
3213 JTR[i] = ssum;
3214 }
3215#endif
3216}
3217
3219 const vpColVector &m_error_prev, const vpHomogeneousMatrix &cMoPrev,
3220 double &mu, bool &reStartFromLastIncrement, vpColVector *const w,
3221 const vpColVector *const m_w_prev)
3222{
3224 if (error.sumSquare() / static_cast<double>(error.getRows()) > m_error_prev.sumSquare() / static_cast<double>(m_error_prev.getRows())) {
3225 mu *= 10.0;
3226
3227 if (mu > 1.0)
3228 throw vpTrackingException(vpTrackingException::fatalError, "Optimization diverged");
3229
3230 m_cMo = cMoPrev;
3231 error = m_error_prev;
3232 if (w != nullptr && m_w_prev != nullptr) {
3233 *w = *m_w_prev;
3234 }
3235 reStartFromLastIncrement = true;
3236 }
3237 }
3238}
3239
3240void vpMbTracker::computeVVSPoseEstimation(const bool isoJoIdentity, unsigned int iter, vpMatrix &L, vpMatrix &LTL,
3241 vpColVector &R, const vpColVector &error, vpColVector &error_prev,
3242 vpColVector &LTR, double &mu, vpColVector &v, const vpColVector *const w,
3243 vpColVector *const m_w_prev)
3244{
3245 if (isoJoIdentity) {
3246 LTL = L.AtA();
3247 computeJTR(L, R, LTR);
3248
3249 switch (m_optimizationMethod) {
3251 vpMatrix LMA(LTL.getRows(), LTL.getCols());
3252 LMA.eye();
3253 vpMatrix LTLmuI = LTL + (LMA * mu);
3254 v = -m_lambda * LTLmuI.pseudoInverse(LTLmuI.getRows() * std::numeric_limits<double>::epsilon()) * LTR;
3255
3256 if (iter != 0)
3257 mu /= 10.0;
3258
3259 error_prev = error;
3260 if (w != nullptr && m_w_prev != nullptr)
3261 *m_w_prev = *w;
3262 break;
3263 }
3264
3266 default:
3267 v = -m_lambda * LTL.pseudoInverse(LTL.getRows() * std::numeric_limits<double>::epsilon()) * LTR;
3268 break;
3269 }
3270 }
3271 else {
3273 cVo.buildFrom(m_cMo);
3274 vpMatrix LVJ = (L * (cVo * oJo));
3275 vpMatrix LVJTLVJ = (LVJ).AtA();
3276 vpColVector LVJTR;
3277 computeJTR(LVJ, R, LVJTR);
3278
3279 switch (m_optimizationMethod) {
3281 vpMatrix LMA(LVJTLVJ.getRows(), LVJTLVJ.getCols());
3282 LMA.eye();
3283 vpMatrix LTLmuI = LVJTLVJ + (LMA * mu);
3284 v = -m_lambda * LTLmuI.pseudoInverse(LTLmuI.getRows() * std::numeric_limits<double>::epsilon()) * LVJTR;
3285 v = cVo * v;
3286
3287 if (iter != 0)
3288 mu /= 10.0;
3289
3290 error_prev = error;
3291 if (w != nullptr && m_w_prev != nullptr)
3292 *m_w_prev = *w;
3293 break;
3294 }
3296 default:
3297 v = -m_lambda * LVJTLVJ.pseudoInverse(LVJTLVJ.getRows() * std::numeric_limits<double>::epsilon()) * LVJTR;
3298 v = cVo * v;
3299 break;
3300 }
3301 }
3302}
3303
3305{
3306 if (error.getRows() > 0)
3307 robust.MEstimator(vpRobust::TUKEY, error, w);
3308}
3309
3322{
3323 vpColVector v(6);
3324 for (unsigned int i = 0; i < 6; i++)
3325 v[i] = oJo[i][i];
3326 return v;
3327}
3328
3345{
3346 if (v.getRows() == 6) {
3347 m_isoJoIdentity = true;
3348 for (unsigned int i = 0; i < 6; i++) {
3349 // if(v[i] != 0){
3350 if (std::fabs(v[i]) > std::numeric_limits<double>::epsilon()) {
3351 oJo[i][i] = 1.0;
3352 }
3353 else {
3354 oJo[i][i] = 0.0;
3355 m_isoJoIdentity = false;
3356 }
3357 }
3358 }
3359}
3360
3361void vpMbTracker::createCylinderBBox(const vpPoint &p1, const vpPoint &p2, const double &radius,
3362 std::vector<std::vector<vpPoint> > &listFaces)
3363{
3364 listFaces.clear();
3365
3366 // std::vector<vpPoint> revolutionAxis;
3367 // revolutionAxis.push_back(p1);
3368 // revolutionAxis.push_back(p2);
3369 // listFaces.push_back(revolutionAxis);
3370
3371 vpColVector axis(3);
3372 axis[0] = p1.get_oX() - p2.get_oX();
3373 axis[1] = p1.get_oY() - p2.get_oY();
3374 axis[2] = p1.get_oZ() - p2.get_oZ();
3375
3376 vpColVector randomVec(3);
3377 randomVec = 0;
3378
3379 vpColVector axisOrtho(3);
3380
3381 randomVec[0] = 1.0;
3382 axisOrtho = vpColVector::crossProd(axis, randomVec);
3383
3384 if (axisOrtho.frobeniusNorm() < std::numeric_limits<double>::epsilon()) {
3385 randomVec = 0;
3386 randomVec[1] = 1.0;
3387 axisOrtho = vpColVector::crossProd(axis, randomVec);
3388 if (axisOrtho.frobeniusNorm() < std::numeric_limits<double>::epsilon()) {
3389 randomVec = 0;
3390 randomVec[2] = 1.0;
3391 axisOrtho = vpColVector::crossProd(axis, randomVec);
3392 if (axisOrtho.frobeniusNorm() < std::numeric_limits<double>::epsilon())
3393 throw vpMatrixException(vpMatrixException::badValue, "Problem in the cylinder definition");
3394 }
3395 }
3396
3397 axisOrtho.normalize();
3398
3399 vpColVector axisOrthoBis(3);
3400 axisOrthoBis = vpColVector::crossProd(axis, axisOrtho);
3401 axisOrthoBis.normalize();
3402
3403 // First circle
3404 vpColVector p1Vec(3);
3405 p1Vec[0] = p1.get_oX();
3406 p1Vec[1] = p1.get_oY();
3407 p1Vec[2] = p1.get_oZ();
3408 vpColVector fc1 = p1Vec + axisOrtho * radius;
3409 vpColVector fc2 = p1Vec + axisOrthoBis * radius;
3410 vpColVector fc3 = p1Vec - axisOrtho * radius;
3411 vpColVector fc4 = p1Vec - axisOrthoBis * radius;
3412
3413 vpColVector p2Vec(3);
3414 p2Vec[0] = p2.get_oX();
3415 p2Vec[1] = p2.get_oY();
3416 p2Vec[2] = p2.get_oZ();
3417 vpColVector sc1 = p2Vec + axisOrtho * radius;
3418 vpColVector sc2 = p2Vec + axisOrthoBis * radius;
3419 vpColVector sc3 = p2Vec - axisOrtho * radius;
3420 vpColVector sc4 = p2Vec - axisOrthoBis * radius;
3421
3422 std::vector<vpPoint> pointsFace;
3423 pointsFace.push_back(vpPoint(fc1[0], fc1[1], fc1[2]));
3424 pointsFace.push_back(vpPoint(sc1[0], sc1[1], sc1[2]));
3425 pointsFace.push_back(vpPoint(sc2[0], sc2[1], sc2[2]));
3426 pointsFace.push_back(vpPoint(fc2[0], fc2[1], fc2[2]));
3427 listFaces.push_back(pointsFace);
3428
3429 pointsFace.clear();
3430 pointsFace.push_back(vpPoint(fc2[0], fc2[1], fc2[2]));
3431 pointsFace.push_back(vpPoint(sc2[0], sc2[1], sc2[2]));
3432 pointsFace.push_back(vpPoint(sc3[0], sc3[1], sc3[2]));
3433 pointsFace.push_back(vpPoint(fc3[0], fc3[1], fc3[2]));
3434 listFaces.push_back(pointsFace);
3435
3436 pointsFace.clear();
3437 pointsFace.push_back(vpPoint(fc3[0], fc3[1], fc3[2]));
3438 pointsFace.push_back(vpPoint(sc3[0], sc3[1], sc3[2]));
3439 pointsFace.push_back(vpPoint(sc4[0], sc4[1], sc4[2]));
3440 pointsFace.push_back(vpPoint(fc4[0], fc4[1], fc4[2]));
3441 listFaces.push_back(pointsFace);
3442
3443 pointsFace.clear();
3444 pointsFace.push_back(vpPoint(fc4[0], fc4[1], fc4[2]));
3445 pointsFace.push_back(vpPoint(sc4[0], sc4[1], sc4[2]));
3446 pointsFace.push_back(vpPoint(sc1[0], sc1[1], sc1[2]));
3447 pointsFace.push_back(vpPoint(fc1[0], fc1[1], fc1[2]));
3448 listFaces.push_back(pointsFace);
3449}
3450
3460bool vpMbTracker::samePoint(const vpPoint &P1, const vpPoint &P2) const
3461{
3462 double dx = fabs(P1.get_oX() - P2.get_oX());
3463 double dy = fabs(P1.get_oY() - P2.get_oY());
3464 double dz = fabs(P1.get_oZ() - P2.get_oZ());
3465
3466 if (dx <= std::numeric_limits<double>::epsilon() && dy <= std::numeric_limits<double>::epsilon() &&
3467 dz <= std::numeric_limits<double>::epsilon())
3468 return true;
3469 else
3470 return false;
3471}
3472
3473void vpMbTracker::addProjectionErrorPolygon(const std::vector<vpPoint> &corners, int idFace,
3474 const std::string &polygonName, bool useLod, double minPolygonAreaThreshold,
3475 double minLineLengthThreshold)
3476{
3477 std::vector<vpPoint> corners_without_duplicates;
3478 corners_without_duplicates.push_back(corners[0]);
3479 for (unsigned int i = 0; i < corners.size() - 1; i++) {
3480 if (std::fabs(corners[i].get_oX() - corners[i + 1].get_oX()) >
3481 std::fabs(corners[i].get_oX()) * std::numeric_limits<double>::epsilon() ||
3482 std::fabs(corners[i].get_oY() - corners[i + 1].get_oY()) >
3483 std::fabs(corners[i].get_oY()) * std::numeric_limits<double>::epsilon() ||
3484 std::fabs(corners[i].get_oZ() - corners[i + 1].get_oZ()) >
3485 std::fabs(corners[i].get_oZ()) * std::numeric_limits<double>::epsilon()) {
3486 corners_without_duplicates.push_back(corners[i + 1]);
3487 }
3488 }
3489
3490 vpMbtPolygon polygon;
3491 polygon.setNbPoint(static_cast<unsigned int>(corners_without_duplicates.size()));
3492 polygon.setIndex(static_cast<int>(idFace));
3493 polygon.setName(polygonName);
3494 polygon.setLod(useLod);
3495
3496 polygon.setMinPolygonAreaThresh(minPolygonAreaThreshold);
3497 polygon.setMinLineLengthThresh(minLineLengthThreshold);
3498
3499 for (unsigned int j = 0; j < corners_without_duplicates.size(); j++) {
3500 polygon.addPoint(j, corners_without_duplicates[j]);
3501 }
3502
3503 m_projectionErrorFaces.addPolygon(&polygon);
3504
3506 m_projectionErrorFaces.getPolygon().back()->setClipping(clippingFlag);
3507
3509 m_projectionErrorFaces.getPolygon().back()->setNearClippingDistance(distNearClip);
3510
3512 m_projectionErrorFaces.getPolygon().back()->setFarClippingDistance(distFarClip);
3513}
3514
3515void vpMbTracker::addProjectionErrorPolygon(const vpPoint &p1, const vpPoint &p2, const vpPoint &p3, double radius,
3516 int idFace, const std::string &polygonName, bool useLod,
3517 double minPolygonAreaThreshold)
3518{
3519 vpMbtPolygon polygon;
3520 polygon.setNbPoint(4);
3521 polygon.setName(polygonName);
3522 polygon.setLod(useLod);
3523
3524 polygon.setMinPolygonAreaThresh(minPolygonAreaThreshold);
3525 // Non sense to set minLineLengthThreshold for circle
3526 // but used to be coherent when applying LOD settings for all polygons
3528
3529 {
3530 // Create the 4 points of the circle bounding box
3531 vpPlane plane(p1, p2, p3, vpPlane::object_frame);
3532
3533 // Matrice de passage entre world et circle frame
3534 double norm_X = sqrt(vpMath::sqr(p2.get_oX() - p1.get_oX()) + vpMath::sqr(p2.get_oY() - p1.get_oY()) +
3535 vpMath::sqr(p2.get_oZ() - p1.get_oZ()));
3536 double norm_Y = sqrt(vpMath::sqr(plane.getA()) + vpMath::sqr(plane.getB()) + vpMath::sqr(plane.getC()));
3537 vpRotationMatrix wRc;
3538 vpColVector x(3), y(3), z(3);
3539 // X axis is P2-P1
3540 x[0] = (p2.get_oX() - p1.get_oX()) / norm_X;
3541 x[1] = (p2.get_oY() - p1.get_oY()) / norm_X;
3542 x[2] = (p2.get_oZ() - p1.get_oZ()) / norm_X;
3543 // Y axis is the normal of the plane
3544 y[0] = plane.getA() / norm_Y;
3545 y[1] = plane.getB() / norm_Y;
3546 y[2] = plane.getC() / norm_Y;
3547 // Z axis = X ^ Y
3548 z = vpColVector::crossProd(x, y);
3549 for (unsigned int i = 0; i < 3; i++) {
3550 wRc[i][0] = x[i];
3551 wRc[i][1] = y[i];
3552 wRc[i][2] = z[i];
3553 }
3554
3555 vpTranslationVector wtc(p1.get_oX(), p1.get_oY(), p1.get_oZ());
3556 vpHomogeneousMatrix wMc(wtc, wRc);
3557
3558 vpColVector c_p(4); // A point in the circle frame that is on the bbox
3559 c_p[0] = radius;
3560 c_p[1] = 0;
3561 c_p[2] = radius;
3562 c_p[3] = 1;
3563
3564 // Matrix to rotate a point by 90 deg around Y in the circle frame
3565 for (unsigned int i = 0; i < 4; i++) {
3566 vpColVector w_p(4); // A point in the word frame
3568 w_p = wMc * cMc_90 * c_p;
3569
3570 vpPoint w_P;
3571 w_P.setWorldCoordinates(w_p[0], w_p[1], w_p[2]);
3572
3573 polygon.addPoint(i, w_P);
3574 }
3575 }
3576
3577 polygon.setIndex(idFace);
3578 m_projectionErrorFaces.addPolygon(&polygon);
3579
3581 m_projectionErrorFaces.getPolygon().back()->setClipping(clippingFlag);
3582
3584 m_projectionErrorFaces.getPolygon().back()->setNearClippingDistance(distNearClip);
3585
3587 m_projectionErrorFaces.getPolygon().back()->setFarClippingDistance(distFarClip);
3588}
3589
3590void vpMbTracker::addProjectionErrorPolygon(const vpPoint &p1, const vpPoint &p2, int idFace,
3591 const std::string &polygonName, bool useLod, double minLineLengthThreshold)
3592{
3593 // A polygon as a single line that corresponds to the revolution axis of the
3594 // cylinder
3595 vpMbtPolygon polygon;
3596 polygon.setNbPoint(2);
3597
3598 polygon.addPoint(0, p1);
3599 polygon.addPoint(1, p2);
3600
3601 polygon.setIndex(idFace);
3602 polygon.setName(polygonName);
3603 polygon.setLod(useLod);
3604
3605 polygon.setMinLineLengthThresh(minLineLengthThreshold);
3606 // Non sense to set minPolygonAreaThreshold for cylinder
3607 // but used to be coherent when applying LOD settings for all polygons
3609
3610 m_projectionErrorFaces.addPolygon(&polygon);
3611
3613 m_projectionErrorFaces.getPolygon().back()->setClipping(clippingFlag);
3614
3616 m_projectionErrorFaces.getPolygon().back()->setNearClippingDistance(distNearClip);
3617
3619 m_projectionErrorFaces.getPolygon().back()->setFarClippingDistance(distFarClip);
3620}
3621
3622void vpMbTracker::addProjectionErrorPolygon(const std::vector<std::vector<vpPoint> > &listFaces, int idFace,
3623 const std::string &polygonName, bool useLod, double minLineLengthThreshold)
3624{
3625 int id = idFace;
3626 for (unsigned int i = 0; i < listFaces.size(); i++) {
3627 vpMbtPolygon polygon;
3628 polygon.setNbPoint(static_cast<unsigned int>(listFaces[i].size()));
3629 for (unsigned int j = 0; j < listFaces[i].size(); j++)
3630 polygon.addPoint(j, listFaces[i][j]);
3631
3632 polygon.setIndex(id);
3633 polygon.setName(polygonName);
3634 polygon.setIsPolygonOriented(false);
3635 polygon.setLod(useLod);
3636 polygon.setMinLineLengthThresh(minLineLengthThreshold);
3638
3639 m_projectionErrorFaces.addPolygon(&polygon);
3640
3642 m_projectionErrorFaces.getPolygon().back()->setClipping(clippingFlag);
3643
3645 m_projectionErrorFaces.getPolygon().back()->setNearClippingDistance(distNearClip);
3646
3648 m_projectionErrorFaces.getPolygon().back()->setFarClippingDistance(distFarClip);
3649
3650 id++;
3651 }
3652}
3653
3654void vpMbTracker::addProjectionErrorLine(vpPoint &P1, vpPoint &P2, int polygon, std::string name)
3655{
3656 // suppress line already in the model
3657 bool already_here = false;
3659
3660 for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_projectionErrorLines.begin();
3661 it != m_projectionErrorLines.end(); ++it) {
3662 l = *it;
3663 if ((samePoint(*(l->p1), P1) && samePoint(*(l->p2), P2)) || (samePoint(*(l->p1), P2) && samePoint(*(l->p2), P1))) {
3664 already_here = true;
3665 l->addPolygon(polygon);
3667 }
3668 }
3669
3670 if (!already_here) {
3671 l = new vpMbtDistanceLine;
3672
3674 l->buildFrom(P1, P2, m_rand);
3675 l->addPolygon(polygon);
3679
3680 l->setIndex(static_cast<unsigned int>(m_projectionErrorLines.size()));
3681 l->setName(name);
3682
3685
3688
3691
3692 m_projectionErrorLines.push_back(l);
3693 }
3694}
3695
3696void vpMbTracker::addProjectionErrorCircle(const vpPoint &P1, const vpPoint &P2, const vpPoint &P3, double r,
3697 int idFace, const std::string &name)
3698{
3699 bool already_here = false;
3701
3702 for (std::vector<vpMbtDistanceCircle *>::const_iterator it = m_projectionErrorCircles.begin();
3703 it != m_projectionErrorCircles.end(); ++it) {
3704 ci = *it;
3705 if ((samePoint(*(ci->p1), P1) && samePoint(*(ci->p2), P2) && samePoint(*(ci->p3), P3)) ||
3706 (samePoint(*(ci->p1), P1) && samePoint(*(ci->p2), P3) && samePoint(*(ci->p3), P2))) {
3707 already_here =
3708 (std::fabs(ci->radius - r) < std::numeric_limits<double>::epsilon() * vpMath::maximum(ci->radius, r));
3709 }
3710 }
3711
3712 if (!already_here) {
3713 ci = new vpMbtDistanceCircle;
3714
3716 ci->buildFrom(P1, P2, P3, r);
3718 ci->setIndex(static_cast<unsigned int>(m_projectionErrorCircles.size()));
3719 ci->setName(name);
3720 ci->index_polygon = idFace;
3722
3723 m_projectionErrorCircles.push_back(ci);
3724 }
3725}
3726
3727void vpMbTracker::addProjectionErrorCylinder(const vpPoint &P1, const vpPoint &P2, double r, int idFace,
3728 const std::string &name)
3729{
3730 bool already_here = false;
3732
3733 for (std::vector<vpMbtDistanceCylinder *>::const_iterator it = m_projectionErrorCylinders.begin();
3734 it != m_projectionErrorCylinders.end(); ++it) {
3735 cy = *it;
3736 if ((samePoint(*(cy->p1), P1) && samePoint(*(cy->p2), P2)) ||
3737 (samePoint(*(cy->p1), P2) && samePoint(*(cy->p2), P1))) {
3738 already_here =
3739 (std::fabs(cy->radius - r) < std::numeric_limits<double>::epsilon() * vpMath::maximum(cy->radius, r));
3740 }
3741 }
3742
3743 if (!already_here) {
3744 cy = new vpMbtDistanceCylinder;
3745
3747 cy->buildFrom(P1, P2, r);
3749 cy->setIndex(static_cast<unsigned int>(m_projectionErrorCylinders.size()));
3750 cy->setName(name);
3751 cy->index_polygon = idFace;
3753 m_projectionErrorCylinders.push_back(cy);
3754 }
3755}
3756
3757void vpMbTracker::initProjectionErrorCircle(const vpPoint &p1, const vpPoint &p2, const vpPoint &p3, double radius,
3758 int idFace, const std::string &name)
3759{
3760 addProjectionErrorCircle(p1, p2, p3, radius, idFace, name);
3761}
3762
3763void vpMbTracker::initProjectionErrorCylinder(const vpPoint &p1, const vpPoint &p2, double radius, int idFace,
3764 const std::string &name)
3765{
3766 addProjectionErrorCylinder(p1, p2, radius, idFace, name);
3767}
3768
3770{
3771 unsigned int nbpt = polygon.getNbPoint();
3772 if (nbpt > 0) {
3773 for (unsigned int i = 0; i < nbpt - 1; i++)
3774 addProjectionErrorLine(polygon.p[i], polygon.p[i + 1], polygon.getIndex(), polygon.getName());
3775 addProjectionErrorLine(polygon.p[nbpt - 1], polygon.p[0], polygon.getIndex(), polygon.getName());
3776 }
3777}
3778
3780{
3781 unsigned int nbpt = polygon.getNbPoint();
3782 if (nbpt > 0) {
3783 for (unsigned int i = 0; i < nbpt - 1; i++)
3784 addProjectionErrorLine(polygon.p[i], polygon.p[i + 1], polygon.getIndex(), polygon.getName());
3785 }
3786}
3787
3806 const vpCameraParameters &_cam)
3807{
3808 if (!modelInitialised) {
3809 throw vpException(vpException::fatalError, "model not initialized");
3810 }
3811
3812 unsigned int nbFeatures = 0;
3813 double totalProjectionError = computeProjectionErrorImpl(I, _cMo, _cam, nbFeatures);
3814
3815 if (nbFeatures > 0) {
3816 return vpMath::deg(totalProjectionError / static_cast<double>(nbFeatures));
3817 }
3818
3819 return 90.0;
3820}
3821
3823 const vpCameraParameters &_cam, unsigned int &nbFeatures)
3824{
3825 bool update_cam = m_projectionErrorCam != _cam;
3826 if (update_cam) {
3827 m_projectionErrorCam = _cam;
3828
3829 for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_projectionErrorLines.begin();
3830 it != m_projectionErrorLines.end(); ++it) {
3831 vpMbtDistanceLine *l = *it;
3833 }
3834
3835 for (std::vector<vpMbtDistanceCylinder *>::const_iterator it = m_projectionErrorCylinders.begin();
3836 it != m_projectionErrorCylinders.end(); ++it) {
3837 vpMbtDistanceCylinder *cy = *it;
3839 }
3840
3841 for (std::vector<vpMbtDistanceCircle *>::const_iterator it = m_projectionErrorCircles.begin();
3842 it != m_projectionErrorCircles.end(); ++it) {
3843 vpMbtDistanceCircle *ci = *it;
3845 }
3846 }
3847
3848#ifdef VISP_HAVE_OGRE
3849 if (useOgre) {
3850 if (update_cam || !m_projectionErrorFaces.isOgreInitialised()) {
3851 m_projectionErrorFaces.setBackgroundSizeOgre(I.getHeight(), I.getWidth());
3854 // Turn off Ogre config dialog display for the next call to this
3855 // function since settings are saved in the ogre.cfg file and used
3856 // during the next call
3858 }
3859 }
3860#endif
3861
3862 if (clippingFlag > 2)
3863 m_projectionErrorCam.computeFov(I.getWidth(), I.getHeight());
3864
3865 projectionErrorVisibleFace(I.getWidth(), I.getHeight(), _cMo);
3866
3868
3869 if (useScanLine) {
3870 if (clippingFlag <= 2)
3871 m_projectionErrorCam.computeFov(I.getWidth(), I.getHeight());
3872
3873 m_projectionErrorFaces.computeClippedPolygons(_cMo, m_projectionErrorCam);
3874 m_projectionErrorFaces.computeScanLineRender(m_projectionErrorCam, I.getWidth(), I.getHeight());
3875 }
3876
3878
3879 double totalProjectionError = 0.0;
3880 for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_projectionErrorLines.begin();
3881 it != m_projectionErrorLines.end(); ++it) {
3882 vpMbtDistanceLine *l = *it;
3883 if (l->isVisible() && l->isTracked()) {
3884 for (size_t a = 0; a < l->meline.size(); a++) {
3885 if (l->meline[a] != nullptr) {
3886 double lineNormGradient;
3887 unsigned int lineNbFeatures;
3888 l->meline[a]->computeProjectionError(I, lineNormGradient, lineNbFeatures, m_SobelX, m_SobelY,
3891 totalProjectionError += lineNormGradient;
3892 nbFeatures += lineNbFeatures;
3893 }
3894 }
3895 }
3896 }
3897
3898 for (std::vector<vpMbtDistanceCylinder *>::const_iterator it = m_projectionErrorCylinders.begin();
3899 it != m_projectionErrorCylinders.end(); ++it) {
3900 vpMbtDistanceCylinder *cy = *it;
3901 if (cy->isVisible() && cy->isTracked()) {
3902 if (cy->meline1 != nullptr) {
3903 double cylinderNormGradient = 0;
3904 unsigned int cylinderNbFeatures = 0;
3905 cy->meline1->computeProjectionError(I, cylinderNormGradient, cylinderNbFeatures, m_SobelX, m_SobelY,
3908 totalProjectionError += cylinderNormGradient;
3909 nbFeatures += cylinderNbFeatures;
3910 }
3911
3912 if (cy->meline2 != nullptr) {
3913 double cylinderNormGradient = 0;
3914 unsigned int cylinderNbFeatures = 0;
3915 cy->meline2->computeProjectionError(I, cylinderNormGradient, cylinderNbFeatures, m_SobelX, m_SobelY,
3918 totalProjectionError += cylinderNormGradient;
3919 nbFeatures += cylinderNbFeatures;
3920 }
3921 }
3922 }
3923
3924 for (std::vector<vpMbtDistanceCircle *>::const_iterator it = m_projectionErrorCircles.begin();
3925 it != m_projectionErrorCircles.end(); ++it) {
3926 vpMbtDistanceCircle *c = *it;
3927 if (c->isVisible() && c->isTracked() && c->meEllipse != nullptr) {
3928 double circleNormGradient = 0;
3929 unsigned int circleNbFeatures = 0;
3930 c->meEllipse->computeProjectionError(I, circleNormGradient, circleNbFeatures, m_SobelX, m_SobelY,
3933 totalProjectionError += circleNormGradient;
3934 nbFeatures += circleNbFeatures;
3935 }
3936 }
3937
3938 return totalProjectionError;
3939}
3940
3941void vpMbTracker::projectionErrorVisibleFace(unsigned int width, unsigned int height, const vpHomogeneousMatrix &_cMo)
3942{
3943 bool changed = false;
3944
3945 if (!useOgre) {
3947 changed);
3948 }
3949 else {
3950#ifdef VISP_HAVE_OGRE
3951 m_projectionErrorFaces.setVisibleOgre(width, height, m_projectionErrorCam, _cMo, angleAppears, angleDisappears,
3952 changed);
3953#else
3955 changed);
3956#endif
3957 }
3958}
3959
3961{
3962 for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_projectionErrorLines.begin();
3963 it != m_projectionErrorLines.end(); ++it) {
3964 for (size_t a = 0; a < (*it)->meline.size(); a++) {
3965 if ((*it)->meline[a] != nullptr) {
3966 delete (*it)->meline[a];
3967 (*it)->meline[a] = nullptr;
3968 }
3969 }
3970
3971 (*it)->meline.clear();
3972 (*it)->nbFeature.clear();
3973 (*it)->nbFeatureTotal = 0;
3974 }
3975
3976 for (std::vector<vpMbtDistanceCylinder *>::const_iterator it = m_projectionErrorCylinders.begin();
3977 it != m_projectionErrorCylinders.end(); ++it) {
3978 if ((*it)->meline1 != nullptr) {
3979 delete (*it)->meline1;
3980 (*it)->meline1 = nullptr;
3981 }
3982 if ((*it)->meline2 != nullptr) {
3983 delete (*it)->meline2;
3984 (*it)->meline2 = nullptr;
3985 }
3986
3987 (*it)->nbFeature = 0;
3988 (*it)->nbFeaturel1 = 0;
3989 (*it)->nbFeaturel2 = 0;
3990 }
3991
3992 for (std::vector<vpMbtDistanceCircle *>::const_iterator it = m_projectionErrorCircles.begin();
3993 it != m_projectionErrorCircles.end(); ++it) {
3994 if ((*it)->meEllipse != nullptr) {
3995 delete (*it)->meEllipse;
3996 (*it)->meEllipse = nullptr;
3997 }
3998 (*it)->nbFeature = 0;
3999 }
4000}
4001
4003{
4004 const bool doNotTrack = true;
4005
4006 for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_projectionErrorLines.begin();
4007 it != m_projectionErrorLines.end(); ++it) {
4008 vpMbtDistanceLine *l = *it;
4009 bool isvisible = false;
4010
4011 for (std::list<int>::const_iterator itindex = l->Lindex_polygon.begin(); itindex != l->Lindex_polygon.end();
4012 ++itindex) {
4013 int index = *itindex;
4014 if (index == -1)
4015 isvisible = true;
4016 else {
4017 if (l->hiddenface->isVisible(static_cast<unsigned int>(index)))
4018 isvisible = true;
4019 }
4020 }
4021
4022 // Si la ligne n'appartient a aucune face elle est tout le temps visible
4023 if (l->Lindex_polygon.empty())
4024 isvisible = true; // Not sure that this can occur
4025
4026 if (isvisible) {
4027 l->setVisible(true);
4028 l->updateTracked();
4029 if (l->meline.empty() && l->isTracked())
4030 l->initMovingEdge(I, _cMo, doNotTrack, m_mask);
4031 }
4032 else {
4033 l->setVisible(false);
4034 for (size_t a = 0; a < l->meline.size(); a++) {
4035 if (l->meline[a] != nullptr)
4036 delete l->meline[a];
4037 if (a < l->nbFeature.size())
4038 l->nbFeature[a] = 0;
4039 }
4040 l->nbFeatureTotal = 0;
4041 l->meline.clear();
4042 l->nbFeature.clear();
4043 }
4044 }
4045
4046 for (std::vector<vpMbtDistanceCylinder *>::const_iterator it = m_projectionErrorCylinders.begin();
4047 it != m_projectionErrorCylinders.end(); ++it) {
4048 vpMbtDistanceCylinder *cy = *it;
4049
4050 bool isvisible = false;
4051
4052 int index = cy->index_polygon;
4053 if (index == -1)
4054 isvisible = true;
4055 else {
4056 if (cy->hiddenface->isVisible(static_cast<unsigned int>(index) + 1) || cy->hiddenface->isVisible(static_cast<unsigned int>(index) + 2) ||
4057 cy->hiddenface->isVisible(static_cast<unsigned int>(index) + 3) || cy->hiddenface->isVisible(static_cast<unsigned int>(index) + 4))
4058 isvisible = true;
4059 }
4060
4061 if (isvisible) {
4062 cy->setVisible(true);
4063 if (cy->meline1 == nullptr || cy->meline2 == nullptr) {
4064 if (cy->isTracked())
4065 cy->initMovingEdge(I, _cMo, doNotTrack, m_mask);
4066 }
4067 }
4068 else {
4069 cy->setVisible(false);
4070 if (cy->meline1 != nullptr)
4071 delete cy->meline1;
4072 if (cy->meline2 != nullptr)
4073 delete cy->meline2;
4074 cy->meline1 = nullptr;
4075 cy->meline2 = nullptr;
4076 cy->nbFeature = 0;
4077 cy->nbFeaturel1 = 0;
4078 cy->nbFeaturel2 = 0;
4079 }
4080 }
4081
4082 for (std::vector<vpMbtDistanceCircle *>::const_iterator it = m_projectionErrorCircles.begin();
4083 it != m_projectionErrorCircles.end(); ++it) {
4084 vpMbtDistanceCircle *ci = *it;
4085 bool isvisible = false;
4086
4087 int index = ci->index_polygon;
4088 if (index == -1)
4089 isvisible = true;
4090 else {
4091 if (ci->hiddenface->isVisible(static_cast<unsigned int>(index)))
4092 isvisible = true;
4093 }
4094
4095 if (isvisible) {
4096 ci->setVisible(true);
4097 if (ci->meEllipse == nullptr) {
4098 if (ci->isTracked())
4099 ci->initMovingEdge(I, _cMo, doNotTrack, m_mask);
4100 }
4101 }
4102 else {
4103 ci->setVisible(false);
4104 if (ci->meEllipse != nullptr)
4105 delete ci->meEllipse;
4106 ci->meEllipse = nullptr;
4107 ci->nbFeature = 0;
4108 }
4109 }
4110}
4111
4112void vpMbTracker::loadConfigFile(const std::string &configFile, bool verbose)
4113{
4114#if defined(VISP_HAVE_PUGIXML)
4116 xmlp.setVerbose(verbose);
4119
4120 try {
4121 if (verbose) {
4122 std::cout << " *********** Parsing XML for ME projection error ************ " << std::endl;
4123 }
4124 xmlp.parse(configFile);
4125 }
4126 catch (...) {
4127 throw vpException(vpException::ioError, "Cannot open XML file \"%s\"", configFile.c_str());
4128 }
4129
4130 vpMe meParser;
4131 xmlp.getProjectionErrorMe(meParser);
4132
4135#else
4136 (void)configFile;
4137 (void)verbose;
4138 throw(vpException(vpException::ioError, "vpMbTracker::loadConfigFile() needs pugixml built-in 3rdparty"));
4139#endif
4140}
4141
4148{
4150
4151 for (std::vector<vpMbtDistanceLine *>::const_iterator it = m_projectionErrorLines.begin();
4152 it != m_projectionErrorLines.end(); ++it) {
4153 vpMbtDistanceLine *l = *it;
4155 }
4156
4157 for (std::vector<vpMbtDistanceCylinder *>::const_iterator it = m_projectionErrorCylinders.begin();
4158 it != m_projectionErrorCylinders.end(); ++it) {
4159 vpMbtDistanceCylinder *cy = *it;
4161 }
4162
4163 for (std::vector<vpMbtDistanceCircle *>::const_iterator it = m_projectionErrorCircles.begin();
4164 it != m_projectionErrorCircles.end(); ++it) {
4165 vpMbtDistanceCircle *ci = *it;
4167 }
4168}
4169
4175void vpMbTracker::setProjectionErrorKernelSize(const unsigned int &size)
4176{
4178
4179 m_SobelX.resize(size * 2 + 1, size * 2 + 1, false, false);
4181
4182 m_SobelY.resize(size * 2 + 1, size * 2 + 1, false, false);
4184}
4185END_VISP_NAMESPACE
unsigned int getCols() const
Definition vpArray2D.h:423
Type * data
Address of the first element of the data array.
Definition vpArray2D.h:149
unsigned int getRows() const
Definition vpArray2D.h:433
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
vpColVector & normalize()
double sumSquare() const
static vpColVector crossProd(const vpColVector &a, const vpColVector &b)
double frobeniusNorm() const
void resize(unsigned int i, bool flagNullify=true)
static const vpColor red
Definition vpColor.h:198
static const vpColor green
Definition vpColor.h:201
Display for windows using GDI (available on any windows 32 platform).
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:135
Class that defines generic functionalities for display.
Definition vpDisplay.h:171
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
int getWindowXPosition() const
Definition vpDisplay.h:234
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, const vpImagePoint &offset=vpImagePoint(0, 0), const std::string &frameName="", const vpColor &textColor=vpColor::black, const vpImagePoint &textOffset=vpImagePoint(15, 15))
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
int getWindowYPosition() const
Definition vpDisplay.h:239
static void flush(const vpImage< unsigned char > &I)
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
unsigned int getDownScalingFactor()
Definition vpDisplay.h:218
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ ioError
I/O error.
Definition vpException.h:67
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:73
@ dimensionError
Bad dimension.
Definition vpException.h:71
@ fatalError
Fatal error.
Definition vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix & buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
static FilterType getSobelKernelY(FilterType *filter, unsigned int size)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
vpDisplay * display
Definition vpImage.h:136
static std::vector< std::string > splitChain(const std::string &chain, const std::string &sep)
static std::string path(const std::string &pathname)
static std::string getAbsolutePathname(const std::string &pathname)
static bool checkFilename(const std::string &filename)
static bool isAbsolutePathname(const std::string &pathname)
static std::string trim(std::string s)
static bool parseBoolean(std::string input)
static std::string createFilePath(const std::string &parent, const std::string &child)
static std::string getParent(const std::string &pathname)
static std::string getName(const std::string &pathname)
Provides simple mathematics computation tools that are not available in the C mathematics library (ma...
Definition vpMath.h:111
static double rad(double deg)
Definition vpMath.h:129
static Type maximum(const Type &a, const Type &b)
Definition vpMath.h:257
static double sqr(double x)
Definition vpMath.h:203
static double deg(double rad)
Definition vpMath.h:119
error that can be emitted by the vpMatrix class and its derivatives
@ incorrectMatrixSizeError
Incorrect matrix size.
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
void diag(const double &val=1.0)
static vpMatrix computeCovarianceMatrixVVS(const vpHomogeneousMatrix &cMo, const vpColVector &deltaS, const vpMatrix &Ls, const vpMatrix &W)
vpMatrix AtA() const
vpMatrix pseudoInverse(double svThreshold=1e-6) const
bool isVisible(unsigned int i)
std::map< std::string, std::string > parseParameters(std::string &endLine)
virtual double computeCurrentProjectionError(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &_cMo, const vpCameraParameters &_cam)
double m_lambda
Gain of the virtual visual servoing stage.
virtual vpColVector getEstimatedDoF() const
double computeProjectionErrorImpl(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &_cMo, const vpCameraParameters &_cam, unsigned int &nbFeatures)
virtual void setEstimatedDoF(const vpColVector &v)
void addProjectionErrorLine(vpPoint &p1, vpPoint &p2, int polygon=-1, std::string name="")
vpCameraParameters m_projectionErrorCam
Camera parameters used for projection error computation.
unsigned int nbPolygonPoints
Number of polygon points in CAO model.
bool modelInitialised
virtual void extractFaces(SoVRMLIndexedFaceSet *face_set, vpHomogeneousMatrix &transform, int &idFace, const std::string &polygonName="")
double minLineLengthThresholdGeneral
Minimum line length threshold for LOD mode (general setting).
bool m_projectionErrorDisplay
Display gradient and model orientation for projection error computation.
void projectionErrorResetMovingEdges()
void initProjectionErrorCircle(const vpPoint &p1, const vpPoint &p2, const vpPoint &p3, double radius, int idFace=0, const std::string &name="")
@ LEVENBERG_MARQUARDT_OPT
virtual void extractCylinders(SoVRMLIndexedFaceSet *face_set, vpHomogeneousMatrix &transform, int &idFace, const std::string &polygonName="")
virtual void setMinLineLengthThresh(double minLineLengthThresh, const std::string &name="")
vpImage< unsigned char > m_I
Grayscale image buffer, used when passing color images.
unsigned int m_projectionErrorDisplayLength
Length of the arrows used to show the gradient and model orientation.
std::vector< vpMbtDistanceCylinder * > m_projectionErrorCylinders
Distance cylinder primitives for projection error.
virtual void loadCAOModel(const std::string &modelFile, std::vector< std::string > &vectorOfModelFilename, int &startIdFace, bool verbose=false, bool parent=true, const vpHomogeneousMatrix &T=vpHomogeneousMatrix())
virtual void init(const vpImage< unsigned char > &I)=0
virtual void initFromPoints(const vpImage< unsigned char > &I, const std::string &initFile)
bool samePoint(const vpPoint &P1, const vpPoint &P2) const
bool useLodGeneral
True if LOD mode is enabled.
double minPolygonAreaThresholdGeneral
Minimum polygon area threshold for LOD mode (general setting).
std::map< std::string, std::string > mapOfParameterNames
bool m_computeInteraction
vpMatrix oJo
The Degrees of Freedom to estimate.
virtual void loadVRMLModel(const std::string &modelFile)
unsigned int nbLines
Number of lines in CAO model.
virtual void setMinPolygonAreaThresh(double minPolygonAreaThresh, const std::string &name="")
virtual void initFaceFromLines(vpMbtPolygon &polygon)=0
void savePose(const std::string &filename) const
void addPolygon(const std::vector< vpPoint > &corners, int idFace=-1, const std::string &polygonName="", bool useLod=false, double minPolygonAreaThreshold=2500.0, double minLineLengthThreshold=50.0)
vpUniRand m_rand
Random number generator used in vpMbtDistanceLine::buildFrom().
vpMatrix covarianceMatrix
Covariance matrix.
double m_initialMu
Initial Mu for Levenberg Marquardt optimization loop.
bool computeProjError
vpHomogeneousMatrix m_cMo
The current pose.
virtual void initCircle(const vpPoint &p1, const vpPoint &p2, const vpPoint &p3, double radius, int idFace=0, const std::string &name="")=0
vpMatrix m_SobelX
Sobel kernel in X.
virtual void initCylinder(const vpPoint &p1, const vpPoint &p2, double radius, int idFace=0, const std::string &name="")=0
virtual void computeVVSCheckLevenbergMarquardt(unsigned int iter, vpColVector &error, const vpColVector &m_error_prev, const vpHomogeneousMatrix &cMoPrev, double &mu, bool &reStartFromLastIncrement, vpColVector *const w=nullptr, const vpColVector *const m_w_prev=nullptr)
unsigned int nbPoints
Number of points in CAO model.
vpCameraParameters m_cam
The camera parameters.
double projectionError
double m_stopCriteriaEpsilon
Epsilon threshold to stop the VVS optimization loop.
std::string modelFileName
bool useOgre
Use Ogre3d for global visibility tests.
virtual void computeVVSWeights(vpRobust &robust, const vpColVector &error, vpColVector &w)
vpMbHiddenFaces< vpMbtPolygon > faces
Set of faces describing the object.
void projectionErrorInitMovingEdge(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &_cMo)
std::vector< vpMbtDistanceCircle * > m_projectionErrorCircles
Distance circle primitive for projection error.
virtual void setOgreVisibilityTest(const bool &v)
std::string poseSavingFilename
void setProjectionErrorKernelSize(const unsigned int &size)
void loadInitFile(const std::string &initFile, std::vector< std::string > &vectorOfInitFilename, bool parent, const vpHomogeneousMatrix &T, std::vector< vpPoint > &P)
void initProjectionErrorCylinder(const vpPoint &p1, const vpPoint &p2, double radius, int idFace=0, const std::string &name="")
virtual void initClick(const vpImage< unsigned char > &I, const std::string &initFile, bool displayHelp=false, const vpHomogeneousMatrix &T=vpHomogeneousMatrix())
unsigned int nbPolygonLines
Number of polygon lines in CAO model.
virtual void setLod(bool useLod, const std::string &name="")
unsigned int m_projectionErrorDisplayThickness
Thickness of the arrows used to show the gradient and model orientation.
virtual void computeCovarianceMatrixVVS(const bool isoJoIdentity, const vpColVector &w_true, const vpHomogeneousMatrix &cMoPrev, const vpMatrix &L_true, const vpMatrix &LVJ_true, const vpColVector &error)
vpMbtOptimizationMethod m_optimizationMethod
Optimization method used.
virtual void computeVVSPoseEstimation(const bool isoJoIdentity, unsigned int iter, vpMatrix &L, vpMatrix &LTL, vpColVector &R, const vpColVector &error, vpColVector &error_prev, vpColVector &LTR, double &mu, vpColVector &v, const vpColVector *const w=nullptr, vpColVector *const m_w_prev=nullptr)
bool displayFeatures
If true, the features are displayed.
virtual void loadModel(const std::string &modelFile, bool verbose=false, const vpHomogeneousMatrix &od_M_o=vpHomogeneousMatrix())
double angleDisappears
Angle used to detect a face disappearance.
virtual void setNearClippingDistance(const double &dist)
void setProjectionErrorMovingEdge(const vpMe &me)
bool applyLodSettingInConfig
virtual void setFarClippingDistance(const double &dist)
double distFarClip
Distance for near clipping.
bool m_isoJoIdentity
Boolean to know if oJo is identity (for fast computation).
void projectionErrorVisibleFace(unsigned int width, unsigned int height, const vpHomogeneousMatrix &_cMo)
unsigned int m_maxInitPoints
Max allowed number of points in init file.
virtual ~vpMbTracker()
void removeCommentsAndEmptyLines(std::ifstream &fileId)
bool useScanLine
Use Scanline for global visibility tests.
void computeJTR(const vpMatrix &J, const vpColVector &R, vpColVector &JTR) const
void addProjectionErrorCylinder(const vpPoint &P1, const vpPoint &P2, double r, int idFace=-1, const std::string &name="")
vpMatrix m_SobelY
Sobel kernel in Y.
virtual void setClipping(const unsigned int &flags)
double angleAppears
Angle used to detect a face appearance.
virtual void display(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const vpColor &col, unsigned int thickness=1, bool displayFullModel=false)=0
bool m_projectionErrorOgreShowConfigDialog
void initProjectionErrorFaceFromCorners(vpMbtPolygon &polygon)
virtual void extractGroup(SoVRMLGroup *sceneGraphVRML2, vpHomogeneousMatrix &transform, int &idFace)
const vpImage< bool > * m_mask
Mask used to disable tracking on a part of image.
virtual void initFromPose(const vpImage< unsigned char > &I, const std::string &initFile)
void addProjectionErrorPolygon(const std::vector< vpPoint > &corners, int idFace=-1, const std::string &polygonName="", bool useLod=false, double minPolygonAreaThreshold=2500.0, const double minLineLengthThreshold=50.0)
unsigned int m_nbInitPoints
Number of points in init file.
bool computeCovariance
Flag used to specify if the covariance matrix has to be computed or not.
void initProjectionErrorFaceFromLines(vpMbtPolygon &polygon)
virtual void extractLines(SoVRMLIndexedLineSet *line_set, int &idFace, const std::string &polygonName="")
virtual std::pair< std::vector< vpPolygon >, std::vector< std::vector< vpPoint > > > getPolygonFaces(bool orderPolygons=true, bool useVisibility=true, bool clipPolygon=false)
std::vector< vpMbtDistanceLine * > m_projectionErrorLines
Distance line primitives for projection error.
double distNearClip
Distance for near clipping.
bool m_sodb_init_called
Flag that indicates that SoDB::init(); was called.
unsigned int m_maxIter
Maximum number of iterations of the virtual visual servoing stage.
bool ogreShowConfigDialog
vpMbTracker & operator=(const vpMbTracker &tracker)
void addProjectionErrorCircle(const vpPoint &P1, const vpPoint &P2, const vpPoint &P3, double r, int idFace=-1, const std::string &name="")
unsigned int nbCylinders
Number of cylinders in CAO model.
unsigned int clippingFlag
Flags specifying which clipping to used.
unsigned int m_projectionErrorKernelSize
Kernel size used to compute the gradient orientation.
unsigned int nbCircles
Number of circles in CAO model.
vpPoint getGravityCenter(const std::vector< vpPoint > &_pts) const
vpMe m_projectionErrorMe
Moving-Edges parameters for projection error.
vpMbHiddenFaces< vpMbtPolygon > m_projectionErrorFaces
Set of faces describing the object, used for projection error.
virtual void initFaceFromCorners(vpMbtPolygon &polygon)=0
void createCylinderBBox(const vpPoint &p1, const vpPoint &p2, const double &radius, std::vector< std::vector< vpPoint > > &listFaces)
virtual void loadConfigFile(const std::string &configFile, bool verbose=true)
Manage a circle used in the model-based tracker.
void setVisible(bool _isvisible)
void setCameraParameters(const vpCameraParameters &camera)
vpMbHiddenFaces< vpMbtPolygon > * hiddenface
Pointer to the list of faces.
vpPoint * p1
The center of the circle.
unsigned int nbFeature
The number of moving edges.
void setIndex(unsigned int i)
void buildFrom(const vpPoint &_p1, const vpPoint &_p2, const vpPoint &_p3, double r)
vpPoint * p2
A point on the plane containing the circle.
bool initMovingEdge(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, bool doNotTrack, const vpImage< bool > *mask=nullptr, const int &initRange=1U)
double radius
The radius of the circle.
int index_polygon
Index of the faces which contain the line.
vpPoint * p3
An other point on the plane containing the circle.
vpMbtMeEllipse * meEllipse
The moving edge containers.
void setName(const std::string &circle_name)
Manage a cylinder used in the model-based tracker.
void buildFrom(const vpPoint &_p1, const vpPoint &_p2, double r)
void setCameraParameters(const vpCameraParameters &camera)
void setName(const std::string &cyl_name)
vpMbtMeLine * meline2
The moving edge containers (second line of the cylinder).
bool initMovingEdge(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, bool doNotTrack, const vpImage< bool > *mask=nullptr, const int &initRange=0)
void setVisible(bool _isvisible)
unsigned int nbFeaturel2
The number of moving edges on line 2.
vpPoint * p2
The second extremity on the axe.
vpMbHiddenFaces< vpMbtPolygon > * hiddenface
Pointer to the list of faces.
double radius
The radius of the cylinder.
unsigned int nbFeaturel1
The number of moving edges on line 1.
unsigned int nbFeature
The number of moving edges.
int index_polygon
Index of the face which contains the cylinder.
void setIndex(unsigned int i)
vpPoint * p1
The first extremity on the axe.
vpMbtMeLine * meline1
The moving edge containers (first line of the cylinder).
Manage the line of a polygon used in the model-based tracker.
void setMovingEdge(vpMe *Me)
std::vector< unsigned int > nbFeature
The number of moving edges.
bool initMovingEdge(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, bool doNotTrack, const vpImage< bool > *mask=nullptr, const int &initRange=0)
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)
unsigned int nbFeatureTotal
The number of moving edges.
vpMbHiddenFaces< vpMbtPolygon > * hiddenface
Pointer to the list of faces.
vpMbtPolygon & getPolygon()
bool useScanLine
Use scanline rendering.
vpPoint * p1
The first extremity.
std::vector< vpMbtMeLine * > meline
The moving edge container.
void setCameraParameters(const vpCameraParameters &camera)
void setName(const std::string &line_name)
void setVisible(bool _isvisible)
void addPolygon(const int &index)
Implementation of a polygon of the model used by the model-based tracker.
void setMinPolygonAreaThresh(double min_polygon_area)
std::string getName() const
void setName(const std::string &face_name)
void setLod(bool use_lod)
virtual void setIndex(int i)
void setMinLineLengthThresh(double min_line_length)
void setIsPolygonOriented(const bool &oriented)
int getIndex() const
Parse an Xml file to extract configuration parameters of a mbtConfig object.
void setProjectionErrorMe(const vpMe &me)
unsigned int getProjectionErrorKernelSize() const
void setProjectionErrorKernelSize(const unsigned int &size)
void parse(const std::string &filename)
void getProjectionErrorMe(vpMe &me) const
Definition vpMe.h:143
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
This class defines the container for a plane geometrical structure.
Definition vpPlane.h:56
@ object_frame
Definition vpPlane.h:64
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:418
void set_x(double x)
Set the point x coordinate in the image plane.
Definition vpPoint.cpp:471
double get_oZ() const
Get the point oZ coordinate in the object frame.
Definition vpPoint.cpp:422
double get_oY() const
Get the point oY coordinate in the object frame.
Definition vpPoint.cpp:420
void setWorldCoordinates(double oX, double oY, double oZ)
Definition vpPoint.cpp:116
void set_y(double y)
Set the point y coordinate in the image plane.
Definition vpPoint.cpp:473
Implements a 3D polygon with render functionalities like clipping.
Definition vpPolygon3D.h:57
void setFarClippingDistance(const double &dist)
unsigned int getNbPoint() const
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
Implementation of a pose vector and operations on poses.
vpPoseVector & buildFrom(const double &tx, const double &ty, const double &tz, const double &tux, const double &tuy, const double &tuz)
Class used for pose computation from N points (pose from point only). Some of the algorithms implemen...
Definition vpPose.h:82
void addPoint(const vpPoint &P)
Definition vpPose.cpp:96
@ DEMENTHON_LAGRANGE_VIRTUAL_VS
Definition vpPose.h:103
bool computePose(vpPoseMethodType method, vpHomogeneousMatrix &cMo, FuncCheckValidityPose func=nullptr)
Definition vpPose.cpp:385
void clearPoint()
Definition vpPose.cpp:89
Implementation of a rotation vector as quaternion angle minimal representation.
Contains an M-estimator and various influence function.
Definition vpRobust.h:84
@ TUKEY
Tukey influence function.
Definition vpRobust.h:89
void MEstimator(const vpRobustEstimatorType method, const vpColVector &residues, vpColVector &weights)
Definition vpRobust.cpp:130
Implementation of a rotation matrix and operations on such kind of matrices.
Implementation of a rotation vector as axis-angle minimal representation.
Error that can be emitted by the vpTracker class and its derivatives.
@ fatalError
Tracker fatal error.
Class that consider the case of a translation vector.
vpVelocityTwistMatrix & buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
#define vpTRACE
Definition vpDebug.h:450
#define vpERROR_TRACE
Definition vpDebug.h:423
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.