1 /****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See http://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Make the complete tracking of an object by using its CAD model
33 *
34 * Authors:
35 * Nicolas Melchior
36 * Romain Tallonneau
37 * Eric Marchand
38 *
39 *****************************************************************************/
40
41 /*!
42 \file vpMbEdgeTracker.cpp
43 \brief Make the complete tracking of an object by using its CAD model.
44 */
45
46 #include <visp3/core/vpDebug.h>
47 #include <visp3/core/vpException.h>
48 #include <visp3/core/vpExponentialMap.h>
49 #include <visp3/core/vpMath.h>
50 #include <visp3/core/vpMatrixException.h>
51 #include <visp3/core/vpPixelMeterConversion.h>
52 #include <visp3/core/vpPolygon3D.h>
53 #include <visp3/core/vpTrackingException.h>
54 #include <visp3/core/vpVelocityTwistMatrix.h>
55 #include <visp3/mbt/vpMbEdgeTracker.h>
56 #include <visp3/mbt/vpMbtDistanceLine.h>
57 #include <visp3/mbt/vpMbtXmlGenericParser.h>
58 #include <visp3/vision/vpPose.h>
59
60 #include <float.h>
61 #include <limits>
62 #include <map>
63 #include <sstream>
64 #include <string>
65
66 /*!
67 Basic constructor
68 */
vpMbEdgeTracker()69 vpMbEdgeTracker::vpMbEdgeTracker()
70 : me(), lines(1), circles(1), cylinders(1), nline(0), ncircle(0), ncylinder(0), nbvisiblepolygone(0),
71 percentageGdPt(0.4), scales(1), Ipyramid(0), scaleLevel(0), nbFeaturesForProjErrorComputation(0), m_factor(),
72 m_robustLines(), m_robustCylinders(), m_robustCircles(), m_wLines(), m_wCylinders(), m_wCircles(), m_errorLines(),
73 m_errorCylinders(), m_errorCircles(), m_L_edge(), m_error_edge(), m_w_edge(), m_weightedError_edge(),
74 m_robust_edge(), m_featuresToBeDisplayedEdge()
75 {
76 scales[0] = true;
77
78 #ifdef VISP_HAVE_OGRE
79 faces.getOgreContext()->setWindowName("MBT Edge");
80 #endif
81 }
82
83 /*!
84 Basic destructor useful to deallocate the memory.
85 */
~vpMbEdgeTracker()86 vpMbEdgeTracker::~vpMbEdgeTracker()
87 {
88 vpMbtDistanceLine *l;
89 vpMbtDistanceCylinder *cy;
90 vpMbtDistanceCircle *ci;
91
92 for (unsigned int i = 0; i < scales.size(); i += 1) {
93 if (scales[i]) {
94 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
95 l = *it;
96 if (l != NULL) {
97 delete l;
98 }
99 l = NULL;
100 }
101
102 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[i].begin(); it != cylinders[i].end();
103 ++it) {
104 cy = *it;
105 if (cy != NULL) {
106 delete cy;
107 }
108 cy = NULL;
109 }
110
111 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
112 ci = *it;
113 if (ci != NULL) {
114 delete ci;
115 }
116 ci = NULL;
117 }
118
119 lines[i].clear();
120 cylinders[i].clear();
121 circles[i].clear();
122 }
123 }
124
125 cleanPyramid(Ipyramid);
126 }
127
128 /*!
129 Set the moving edge parameters.
130
131 \param p_me : an instance of vpMe containing all the desired parameters
132 */
setMovingEdge(const vpMe & p_me)133 void vpMbEdgeTracker::setMovingEdge(const vpMe &p_me)
134 {
135 this->me = p_me;
136
137 for (unsigned int i = 0; i < scales.size(); i += 1) {
138 if (scales[i]) {
139 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
140 vpMbtDistanceLine *l = *it;
141 l->setMovingEdge(&(this->me));
142 }
143
144 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[i].begin(); it != cylinders[i].end();
145 ++it) {
146 vpMbtDistanceCylinder *cy = *it;
147 cy->setMovingEdge(&(this->me));
148 }
149
150 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
151 vpMbtDistanceCircle *ci = *it;
152 ci->setMovingEdge(&(this->me));
153 }
154 }
155 }
156 }
157
158 /*!
159 Compute the visual servoing loop to get the pose of the feature set.
160
161 \exception vpTrackingException::notEnoughPointError if the number of
162 detected feature is equal to zero.
163
164 \param _I : The current image.
165 \param lvl : The level in the pyramid scale.
166 */
computeVVS(const vpImage<unsigned char> & _I,unsigned int lvl)167 void vpMbEdgeTracker::computeVVS(const vpImage<unsigned char> &_I, unsigned int lvl)
168 {
169 double residu_1 = 1e3;
170 double r = 1e3 - 1;
171
172 unsigned int iter = 0;
173
174 computeVVSInit();
175 unsigned int nbrow = m_error_edge.getRows();
176
177 bool reloop = true;
178
179 bool isoJoIdentity_ = isoJoIdentity; // Backup since it can be modified if L is not full rank
180 if (isoJoIdentity_)
181 oJo.eye();
182
183 /*** First phase ***/
184
185 while (reloop == true && iter < 10) {
186 double count = 0;
187
188 computeVVSFirstPhase(_I, iter, count, lvl);
189
190 count = count / (double)nbrow;
191 if (count >= 0.85) {
192 reloop = false;
193 }
194
195 computeVVSFirstPhasePoseEstimation(iter, isoJoIdentity_);
196
197 iter++;
198 }
199
200 // std::cout << "\t First minimization in " << iter << " iteration give as
201 // initial cMo: \n" << cMo << std::endl;
202
203 /*** Second phase ***/
204 vpHomogeneousMatrix cMoPrev;
205 vpColVector W_true(nbrow);
206 vpMatrix L_true;
207 vpMatrix LVJ_true;
208
209 double mu = m_initialMu;
210 vpColVector m_error_prev;
211 vpColVector m_w_prev;
212
213 // To avoid to create these matrices each iteration
214 vpMatrix LTL;
215 vpColVector LTR;
216 vpColVector v;
217
218 iter = 0;
219 m_w_edge = 1;
220
221 // while ( ((int)((residu_1 - r)*1e8) !=0 ) && (iter<30))
222 while (std::fabs((residu_1 - r) * 1e8) > std::numeric_limits<double>::epsilon() && (iter < m_maxIter)) {
223 computeVVSInteractionMatrixAndResidu(_I);
224
225 bool reStartFromLastIncrement = false;
226 computeVVSCheckLevenbergMarquardt(iter, m_error_edge, m_error_prev, cMoPrev, mu, reStartFromLastIncrement,
227 &m_w_edge, &m_w_prev);
228
229 if (!reStartFromLastIncrement) {
230 computeVVSWeights();
231
232 L_true = m_L_edge;
233 vpVelocityTwistMatrix cVo;
234
235 if (computeCovariance) {
236 L_true = m_L_edge;
237 if (!isoJoIdentity_) {
238 cVo.buildFrom(m_cMo);
239 LVJ_true = (m_L_edge * cVo * oJo);
240 }
241 }
242
243 double wi = 0.0, eri = 0.0;
244 double num = 0.0, den = 0.0;
245 if ((iter == 0) || m_computeInteraction) {
246 for (unsigned int i = 0; i < nbrow; i++) {
247 wi = m_w_edge[i] * m_factor[i];
248 W_true[i] = wi;
249 eri = m_error_edge[i];
250 num += wi * vpMath::sqr(eri);
251 den += wi;
252
253 m_weightedError_edge[i] = wi * eri;
254
255 for (unsigned int j = 0; j < 6; j++) {
256 m_L_edge[i][j] = wi * m_L_edge[i][j];
257 }
258 }
259 } else {
260 for (unsigned int i = 0; i < nbrow; i++) {
261 wi = m_w_edge[i] * m_factor[i];
262 W_true[i] = wi;
263 eri = m_error_edge[i];
264 num += wi * vpMath::sqr(eri);
265 den += wi;
266
267 m_weightedError_edge[i] = wi * eri;
268 }
269 }
270
271 residu_1 = r;
272 r = sqrt(num / den); // Le critere d'arret prend en compte le poids
273
274 computeVVSPoseEstimation(isoJoIdentity_, iter, m_L_edge, LTL, m_weightedError_edge, m_error_edge, m_error_prev,
275 LTR, mu, v, &m_w_edge, &m_w_prev);
276
277 cMoPrev = m_cMo;
278 m_cMo = vpExponentialMap::direct(v).inverse() * m_cMo;
279
280 } // endif(!restartFromLast)
281
282 iter++;
283 }
284
285 computeCovarianceMatrixVVS(isoJoIdentity_, W_true, cMoPrev, L_true, LVJ_true, m_error_edge);
286
287 updateMovingEdgeWeights();
288 }
289
computeVVSFirstPhase(const vpImage<unsigned char> & _I,unsigned int iter,double & count,unsigned int lvl)290 void vpMbEdgeTracker::computeVVSFirstPhase(const vpImage<unsigned char> &_I, unsigned int iter, double &count,
291 unsigned int lvl)
292 {
293 vpMbtDistanceLine *l;
294 vpMbtDistanceCylinder *cy;
295 vpMbtDistanceCircle *ci;
296
297 double limite = 3; // Une limite de 3 pixels
298 limite = limite / m_cam.get_px(); // Transformation limite pixel en limite metre.
299
300 unsigned int n = 0;
301
302 // Parametre pour la premiere phase d'asservissement
303 double e_prev = 0, e_cur, e_next;
304
305 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[lvl].begin(); it != lines[lvl].end(); ++it) {
306 if ((*it)->isTracked()) {
307 l = *it;
308 l->computeInteractionMatrixError(m_cMo);
309
310 double fac = 1;
311 if (iter == 0) {
312 for (std::list<int>::const_iterator itindex = l->Lindex_polygon.begin(); itindex != l->Lindex_polygon.end();
313 ++itindex) {
314 int index = *itindex;
315 if (l->hiddenface->isAppearing((unsigned int)index)) {
316 fac = 0.2;
317 break;
318 }
319 if (l->closeToImageBorder(_I, 10)) {
320 fac = 0.1;
321 break;
322 }
323 }
324 }
325
326 std::list<vpMeSite>::const_iterator itListLine;
327
328 unsigned int indexFeature = 0;
329
330 for (size_t a = 0; a < l->meline.size(); a++) {
331 if (iter == 0 && l->meline[a] != NULL)
332 itListLine = l->meline[a]->getMeList().begin();
333
334 for (unsigned int i = 0; i < l->nbFeature[a]; i++) {
335 for (unsigned int j = 0; j < 6; j++) {
336 m_L_edge[n + i][j] = l->L[indexFeature][j]; // On remplit la matrice d'interaction globale
337 }
338 m_error_edge[n + i] = l->error[indexFeature]; // On remplit la matrice d'erreur
339
340 if (m_error_edge[n + i] <= limite)
341 count = count + 1.0; // Si erreur proche de 0 on incremente cur
342
343 m_w_edge[n + i] = 0;
344
345 if (iter == 0) {
346 m_factor[n + i] = fac;
347 vpMeSite site = *itListLine;
348 if (site.getState() != vpMeSite::NO_SUPPRESSION)
349 m_factor[n + i] = 0.2;
350 ++itListLine;
351 }
352
353 // If pour la premiere extremite des moving edges
354 if (indexFeature == 0) {
355 e_cur = l->error[0];
356 if (l->nbFeature[a] > 1) {
357 e_next = l->error[1];
358 if (fabs(e_cur - e_next) < limite && vpMath::sign(e_cur) == vpMath::sign(e_next)) {
359 m_w_edge[n + i] = 1 /*0.5*/;
360 }
361 e_prev = e_cur;
362 } else
363 m_w_edge[n + i] = 1;
364 }
365
366 // If pour la derniere extremite des moving edges
367 else if (indexFeature == l->nbFeatureTotal - 1) {
368 e_cur = l->error[indexFeature];
369 if (fabs(e_cur - e_prev) < limite && vpMath::sign(e_cur) == vpMath::sign(e_prev)) {
370 m_w_edge[n + i] += 1 /*0.5*/;
371 }
372 }
373
374 else {
375 e_cur = l->error[indexFeature];
376 e_next = l->error[indexFeature + 1];
377 if (fabs(e_cur - e_prev) < limite) {
378 m_w_edge[n + i] += 0.5;
379 }
380 if (fabs(e_cur - e_next) < limite) {
381 m_w_edge[n + i] += 0.5;
382 }
383 e_prev = e_cur;
384 }
385 indexFeature++;
386 }
387 n += l->nbFeature[a];
388 }
389 }
390 }
391
392 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[lvl].begin(); it != cylinders[lvl].end();
393 ++it) {
394 if ((*it)->isTracked()) {
395 cy = *it;
396 cy->computeInteractionMatrixError(m_cMo, _I);
397 double fac = 1.0;
398
399 std::list<vpMeSite>::const_iterator itCyl1;
400 std::list<vpMeSite>::const_iterator itCyl2;
401 if (iter == 0 && (cy->meline1 != NULL || cy->meline2 != NULL)) {
402 itCyl1 = cy->meline1->getMeList().begin();
403 itCyl2 = cy->meline2->getMeList().begin();
404 }
405
406 for (unsigned int i = 0; i < cy->nbFeature; i++) {
407 for (unsigned int j = 0; j < 6; j++) {
408 m_L_edge[n + i][j] = cy->L[i][j]; // On remplit la matrice d'interaction globale
409 }
410 m_error_edge[n + i] = cy->error[i]; // On remplit la matrice d'erreur
411
412 if (m_error_edge[n + i] <= limite)
413 count = count + 1.0; // Si erreur proche de 0 on incremente cur
414
415 m_w_edge[n + i] = 0;
416
417 if (iter == 0) {
418 m_factor[n + i] = fac;
419 vpMeSite site;
420 if (i < cy->nbFeaturel1) {
421 site = *itCyl1;
422 ++itCyl1;
423 } else {
424 site = *itCyl2;
425 ++itCyl2;
426 }
427 if (site.getState() != vpMeSite::NO_SUPPRESSION)
428 m_factor[n + i] = 0.2;
429 }
430
431 // If pour la premiere extremite des moving edges
432 if (i == 0) {
433 e_cur = cy->error[0];
434 if (cy->nbFeature > 1) {
435 e_next = cy->error[1];
436 if (fabs(e_cur - e_next) < limite && vpMath::sign(e_cur) == vpMath::sign(e_next)) {
437 m_w_edge[n + i] = 1 /*0.5*/;
438 }
439 e_prev = e_cur;
440 } else
441 m_w_edge[n + i] = 1;
442 }
443 if (i == cy->nbFeaturel1) {
444 e_cur = cy->error[i];
445 if (cy->nbFeaturel2 > 1) {
446 e_next = cy->error[i + 1];
447 if (fabs(e_cur - e_next) < limite && vpMath::sign(e_cur) == vpMath::sign(e_next)) {
448 m_w_edge[n + i] = 1 /*0.5*/;
449 }
450 e_prev = e_cur;
451 } else
452 m_w_edge[n + i] = 1;
453 }
454
455 // If pour la derniere extremite des moving edges
456 else if (i == cy->nbFeaturel1 - 1) {
457 e_cur = cy->error[i];
458 if (fabs(e_cur - e_prev) < limite && vpMath::sign(e_cur) == vpMath::sign(e_prev)) {
459 m_w_edge[n + i] += 1 /*0.5*/;
460 }
461 }
462 // If pour la derniere extremite des moving edges
463 else if (i == cy->nbFeature - 1) {
464 e_cur = cy->error[i];
465 if (fabs(e_cur - e_prev) < limite && vpMath::sign(e_cur) == vpMath::sign(e_prev)) {
466 m_w_edge[n + i] += 1 /*0.5*/;
467 }
468 }
469
470 else {
471 e_cur = cy->error[i];
472 e_next = cy->error[i + 1];
473 if (fabs(e_cur - e_prev) < limite) {
474 m_w_edge[n + i] += 0.5;
475 }
476 if (fabs(e_cur - e_next) < limite) {
477 m_w_edge[n + i] += 0.5;
478 }
479 e_prev = e_cur;
480 }
481 }
482
483 n += cy->nbFeature;
484 }
485 }
486
487 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[lvl].begin(); it != circles[lvl].end(); ++it) {
488 if ((*it)->isTracked()) {
489 ci = *it;
490 ci->computeInteractionMatrixError(m_cMo);
491 double fac = 1.0;
492
493 std::list<vpMeSite>::const_iterator itCir;
494 if (iter == 0 && (ci->meEllipse != NULL)) {
495 itCir = ci->meEllipse->getMeList().begin();
496 }
497
498 for (unsigned int i = 0; i < ci->nbFeature; i++) {
499 for (unsigned int j = 0; j < 6; j++) {
500 m_L_edge[n + i][j] = ci->L[i][j]; // On remplit la matrice d'interaction globale
501 }
502 m_error_edge[n + i] = ci->error[i]; // On remplit la matrice d'erreur
503
504 if (m_error_edge[n + i] <= limite)
505 count = count + 1.0; // Si erreur proche de 0 on incremente cur
506
507 m_w_edge[n + i] = 0;
508
509 if (iter == 0) {
510 m_factor[n + i] = fac;
511 vpMeSite site = *itCir;
512 if (site.getState() != vpMeSite::NO_SUPPRESSION)
513 m_factor[n + i] = 0.2;
514 ++itCir;
515 }
516
517 // If pour la premiere extremite des moving edges
518 if (i == 0) {
519 e_cur = ci->error[0];
520 if (ci->nbFeature > 1) {
521 e_next = ci->error[1];
522 if (fabs(e_cur - e_next) < limite && vpMath::sign(e_cur) == vpMath::sign(e_next)) {
523 m_w_edge[n + i] = 1 /*0.5*/;
524 }
525 e_prev = e_cur;
526 } else
527 m_w_edge[n + i] = 1;
528 }
529
530 // If pour la derniere extremite des moving edges
531 else if (i == ci->nbFeature - 1) {
532 e_cur = ci->error[i];
533 if (fabs(e_cur - e_prev) < limite && vpMath::sign(e_cur) == vpMath::sign(e_prev)) {
534 m_w_edge[n + i] += 1 /*0.5*/;
535 }
536 }
537
538 else {
539 e_cur = ci->error[i];
540 e_next = ci->error[i + 1];
541 if (fabs(e_cur - e_prev) < limite) {
542 m_w_edge[n + i] += 0.5;
543 }
544 if (fabs(e_cur - e_next) < limite) {
545 m_w_edge[n + i] += 0.5;
546 }
547 e_prev = e_cur;
548 }
549 }
550
551 n += ci->nbFeature;
552 }
553 }
554 }
555
computeVVSFirstPhaseFactor(const vpImage<unsigned char> & I,unsigned int lvl)556 void vpMbEdgeTracker::computeVVSFirstPhaseFactor(const vpImage<unsigned char> &I, unsigned int lvl)
557 {
558 vpMbtDistanceLine *l;
559 vpMbtDistanceCylinder *cy;
560 vpMbtDistanceCircle *ci;
561
562 unsigned int n = 0;
563 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[lvl].begin(); it != lines[lvl].end(); ++it) {
564 if ((*it)->isTracked()) {
565 l = *it;
566 l->computeInteractionMatrixError(m_cMo);
567
568 double fac = 1;
569 for (std::list<int>::const_iterator itindex = l->Lindex_polygon.begin(); itindex != l->Lindex_polygon.end();
570 ++itindex) {
571 int index = *itindex;
572 if (l->hiddenface->isAppearing((unsigned int)index)) {
573 fac = 0.2;
574 break;
575 }
576 if (l->closeToImageBorder(I, 10)) {
577 fac = 0.1;
578 break;
579 }
580 }
581
582 unsigned int indexFeature = 0;
583 for (size_t a = 0; a < l->meline.size(); a++) {
584 std::list<vpMeSite>::const_iterator itListLine;
585 if (l->meline[a] != NULL) {
586 itListLine = l->meline[a]->getMeList().begin();
587
588 for (unsigned int i = 0; i < l->nbFeature[a]; i++) {
589 m_factor[n + i] = fac;
590 vpMeSite site = *itListLine;
591 if (site.getState() != vpMeSite::NO_SUPPRESSION)
592 m_factor[n + i] = 0.2;
593 ++itListLine;
594 indexFeature++;
595 }
596 n += l->nbFeature[a];
597 }
598 }
599 }
600 }
601
602 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[lvl].begin(); it != cylinders[lvl].end();
603 ++it) {
604 if ((*it)->isTracked()) {
605 cy = *it;
606 cy->computeInteractionMatrixError(m_cMo, I);
607
608 std::list<vpMeSite>::const_iterator itCyl1;
609 std::list<vpMeSite>::const_iterator itCyl2;
610 if ((cy->meline1 != NULL || cy->meline2 != NULL)) {
611 itCyl1 = cy->meline1->getMeList().begin();
612 itCyl2 = cy->meline2->getMeList().begin();
613
614 double fac = 1.0;
615 for (unsigned int i = 0; i < cy->nbFeature; i++) {
616 m_factor[n + i] = fac;
617 vpMeSite site;
618 if (i < cy->nbFeaturel1) {
619 site = *itCyl1;
620 ++itCyl1;
621 } else {
622 site = *itCyl2;
623 ++itCyl2;
624 }
625 if (site.getState() != vpMeSite::NO_SUPPRESSION)
626 m_factor[n + i] = 0.2;
627 }
628 n += cy->nbFeature;
629 }
630 }
631 }
632
633 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[lvl].begin(); it != circles[lvl].end(); ++it) {
634 if ((*it)->isTracked()) {
635 ci = *it;
636 ci->computeInteractionMatrixError(m_cMo);
637
638 std::list<vpMeSite>::const_iterator itCir;
639 if (ci->meEllipse != NULL) {
640 itCir = ci->meEllipse->getMeList().begin();
641 double fac = 1.0;
642
643 for (unsigned int i = 0; i < ci->nbFeature; i++) {
644 m_factor[n + i] = fac;
645 vpMeSite site = *itCir;
646 if (site.getState() != vpMeSite::NO_SUPPRESSION)
647 m_factor[n + i] = 0.2;
648 ++itCir;
649 }
650 n += ci->nbFeature;
651 }
652 }
653 }
654 }
655
computeVVSFirstPhasePoseEstimation(unsigned int iter,bool & isoJoIdentity_)656 void vpMbEdgeTracker::computeVVSFirstPhasePoseEstimation(unsigned int iter, bool &isoJoIdentity_)
657 {
658 unsigned int nerror = m_weightedError_edge.getRows();
659
660 double wi, eri;
661 if ((iter == 0) || m_computeInteraction) {
662 for (unsigned int i = 0; i < nerror; i++) {
663 wi = m_w_edge[i] * m_factor[i];
664 eri = m_error_edge[i];
665
666 m_weightedError_edge[i] = wi * eri;
667
668 for (unsigned int j = 0; j < 6; j++) {
669 m_L_edge[i][j] = wi * m_L_edge[i][j];
670 }
671 }
672 } else {
673 for (unsigned int i = 0; i < nerror; i++) {
674 wi = m_w_edge[i] * m_factor[i];
675 eri = m_error_edge[i];
676
677 m_weightedError_edge[i] = wi * eri;
678 }
679 }
680
681 vpVelocityTwistMatrix cVo;
682
683 // If all the 6 dof should be estimated, we check if the interaction matrix
684 // is full rank. If not we remove automatically the dof that cannot be
685 // estimated This is particularly useful when consering circles (rank 5) and
686 // cylinders (rank 4)
687 if (isoJoIdentity_) {
688 cVo.buildFrom(m_cMo);
689
690 vpMatrix K; // kernel
691 unsigned int rank = (m_L_edge * cVo).kernel(K);
692 if (rank == 0) {
693 throw vpException(vpException::fatalError, "Rank=0, cannot estimate the pose !");
694 }
695 if (rank != 6) {
696 vpMatrix I; // Identity
697 I.eye(6);
698 oJo = I - K.AtA();
699
700 isoJoIdentity_ = false;
701 }
702 }
703
704 vpColVector v;
705 vpMatrix LTL;
706 vpColVector LTR;
707
708 if (isoJoIdentity_) {
709 LTL = m_L_edge.AtA();
710 computeJTR(m_L_edge, m_weightedError_edge, LTR);
711 v = -0.7 * LTL.pseudoInverse(LTL.getRows() * std::numeric_limits<double>::epsilon()) * LTR;
712 } else {
713 cVo.buildFrom(m_cMo);
714 vpMatrix LVJ = (m_L_edge * cVo * oJo);
715 vpMatrix LVJTLVJ = (LVJ).AtA();
716 vpColVector LVJTR;
717 computeJTR(LVJ, m_weightedError_edge, LVJTR);
718 v = -0.7 * LVJTLVJ.pseudoInverse(LVJTLVJ.getRows() * std::numeric_limits<double>::epsilon()) * LVJTR;
719 v = cVo * v;
720 }
721
722 m_cMo = vpExponentialMap::direct(v).inverse() * m_cMo;
723 }
724
computeVVSInit()725 void vpMbEdgeTracker::computeVVSInit()
726 {
727 // Nombre de moving edges
728 unsigned int nbrow = 0;
729 unsigned int nberrors_lines = 0;
730 unsigned int nberrors_cylinders = 0;
731 unsigned int nberrors_circles = 0;
732
733 nbrow = initMbtTracking(nberrors_lines, nberrors_cylinders, nberrors_circles);
734
735 if (nbrow == 0) {
736 throw vpTrackingException(vpTrackingException::notEnoughPointError,
737 "No data found to compute the interaction matrix...");
738 }
739
740 m_L_edge.resize(nbrow, 6, false, false);
741 m_error_edge.resize(nbrow, false);
742
743 m_weightedError_edge.resize(nbrow, false);
744 m_w_edge.resize(nbrow, false);
745 m_w_edge = 1;
746 m_factor.resize(nbrow, false);
747 m_factor = 1;
748
749 m_robustLines.setMinMedianAbsoluteDeviation(2.0 / m_cam.get_px());
750 m_robustCylinders.setMinMedianAbsoluteDeviation(2.0 / m_cam.get_px());
751 m_robustCircles.setMinMedianAbsoluteDeviation(vpMath::sqr(2.0 / m_cam.get_px()));
752
753 m_wLines.resize(nberrors_lines, false);
754 m_wLines = 1;
755 m_wCylinders.resize(nberrors_cylinders, false);
756 m_wCylinders = 1;
757 m_wCircles.resize(nberrors_circles, false);
758 m_wCircles = 1;
759
760 m_errorLines.resize(nberrors_lines, false);
761 m_errorCylinders.resize(nberrors_cylinders, false);
762 m_errorCircles.resize(nberrors_circles, false);
763 }
764
computeVVSInteractionMatrixAndResidu()765 void vpMbEdgeTracker::computeVVSInteractionMatrixAndResidu()
766 {
767 throw vpException(vpException::fatalError, "vpMbEdgeTracker::"
768 "computeVVSInteractionMatrixAndR"
769 "esidu() should not be called!");
770 }
771
computeVVSInteractionMatrixAndResidu(const vpImage<unsigned char> & _I)772 void vpMbEdgeTracker::computeVVSInteractionMatrixAndResidu(const vpImage<unsigned char> &_I)
773 {
774 vpMbtDistanceLine *l;
775 vpMbtDistanceCylinder *cy;
776 vpMbtDistanceCircle *ci;
777
778 unsigned int n = 0;
779 unsigned int nlines = 0;
780 unsigned int ncylinders = 0;
781 unsigned int ncircles = 0;
782
783 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
784 ++it) {
785 if ((*it)->isTracked()) {
786 l = *it;
787 l->computeInteractionMatrixError(m_cMo);
788 for (unsigned int i = 0; i < l->nbFeatureTotal; i++) {
789 for (unsigned int j = 0; j < 6; j++) {
790 m_L_edge[n + i][j] = l->L[i][j];
791 m_error_edge[n + i] = l->error[i];
792 m_errorLines[nlines + i] = m_error_edge[n + i];
793 }
794 }
795 n += l->nbFeatureTotal;
796 nlines += l->nbFeatureTotal;
797 }
798 }
799
800 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
801 it != cylinders[scaleLevel].end(); ++it) {
802 if ((*it)->isTracked()) {
803 cy = *it;
804 cy->computeInteractionMatrixError(m_cMo, _I);
805 for (unsigned int i = 0; i < cy->nbFeature; i++) {
806 for (unsigned int j = 0; j < 6; j++) {
807 m_L_edge[n + i][j] = cy->L[i][j];
808 m_error_edge[n + i] = cy->error[i];
809 m_errorCylinders[ncylinders + i] = m_error_edge[n + i];
810 }
811 }
812
813 n += cy->nbFeature;
814 ncylinders += cy->nbFeature;
815 }
816 }
817
818 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
819 it != circles[scaleLevel].end(); ++it) {
820 if ((*it)->isTracked()) {
821 ci = *it;
822 ci->computeInteractionMatrixError(m_cMo);
823 for (unsigned int i = 0; i < ci->nbFeature; i++) {
824 for (unsigned int j = 0; j < 6; j++) {
825 m_L_edge[n + i][j] = ci->L[i][j];
826 m_error_edge[n + i] = ci->error[i];
827 m_errorCircles[ncircles + i] = m_error_edge[n + i];
828 }
829 }
830
831 n += ci->nbFeature;
832 ncircles += ci->nbFeature;
833 }
834 }
835 }
836
computeVVSWeights()837 void vpMbEdgeTracker::computeVVSWeights()
838 {
839 unsigned int nberrors_lines = m_errorLines.getRows(), nberrors_cylinders = m_errorCylinders.getRows(),
840 nberrors_circles = m_errorCircles.getRows();
841
842 if (nberrors_lines > 0)
843 m_robustLines.MEstimator(vpRobust::TUKEY, m_errorLines, m_wLines);
844 if (nberrors_cylinders > 0)
845 m_robustCylinders.MEstimator(vpRobust::TUKEY, m_errorCylinders, m_wCylinders);
846 if (nberrors_circles > 0)
847 m_robustCircles.MEstimator(vpRobust::TUKEY, m_errorCircles, m_wCircles);
848
849 m_w_edge.insert(0, m_wLines);
850 m_w_edge.insert(m_wLines.getRows(), m_wCylinders);
851 m_w_edge.insert(m_wLines.getRows() + m_wCylinders.getRows(), m_wCircles);
852 }
853
854 /*!
855 Compute the projection error of the model.
856 This approach compares the gradient direction around samples of each lines
857 of the model with their direction. Error is expressed in degrees between 0
858 and 90.
859
860 \param _I : Image in which the model appears.
861 */
computeProjectionError(const vpImage<unsigned char> & _I)862 void vpMbEdgeTracker::computeProjectionError(const vpImage<unsigned char> &_I)
863 {
864 projectionError = 0.0;
865 unsigned int nbFeatures = 0;
866 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
867 ++it) {
868 vpMbtDistanceLine *l = *it;
869 if (l->isVisible() && l->isTracked()) {
870 for (size_t a = 0; a < l->meline.size(); a++) {
871 if (l->meline[a] != NULL) {
872 double lineNormGradient;
873 unsigned int lineNbFeatures;
874 l->meline[a]->computeProjectionError(_I, lineNormGradient, lineNbFeatures, m_SobelX, m_SobelY,
875 m_projectionErrorDisplay, m_projectionErrorDisplayLength,
876 m_projectionErrorDisplayThickness);
877 projectionError += lineNormGradient;
878 nbFeatures += lineNbFeatures;
879 }
880 }
881 }
882 }
883
884 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
885 it != cylinders[scaleLevel].end(); ++it) {
886 vpMbtDistanceCylinder *cy = *it;
887 if (cy->isVisible() && cy->isTracked()) {
888 if (cy->meline1 != NULL) {
889 double cylinderNormGradient = 0;
890 unsigned int cylinderNbFeatures = 0;
891 cy->meline1->computeProjectionError(_I, cylinderNormGradient, cylinderNbFeatures, m_SobelX, m_SobelY,
892 m_projectionErrorDisplay, m_projectionErrorDisplayLength,
893 m_projectionErrorDisplayThickness);
894 projectionError += cylinderNormGradient;
895 nbFeatures += cylinderNbFeatures;
896 }
897
898 if (cy->meline2 != NULL) {
899 double cylinderNormGradient = 0;
900 unsigned int cylinderNbFeatures = 0;
901 cy->meline2->computeProjectionError(_I, cylinderNormGradient, cylinderNbFeatures, m_SobelX, m_SobelY,
902 m_projectionErrorDisplay, m_projectionErrorDisplayLength,
903 m_projectionErrorDisplayThickness);
904 projectionError += cylinderNormGradient;
905 nbFeatures += cylinderNbFeatures;
906 }
907 }
908 }
909
910 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
911 it != circles[scaleLevel].end(); ++it) {
912 vpMbtDistanceCircle *c = *it;
913 if (c->isVisible() && c->isTracked() && c->meEllipse != NULL) {
914 double circleNormGradient = 0;
915 unsigned int circleNbFeatures = 0;
916 c->meEllipse->computeProjectionError(_I, circleNormGradient, circleNbFeatures, m_SobelX, m_SobelY,
917 m_projectionErrorDisplay, m_projectionErrorDisplayLength,
918 m_projectionErrorDisplayThickness);
919 projectionError += circleNormGradient;
920 nbFeatures += circleNbFeatures;
921 }
922 }
923
924 if (nbFeatures > 0) {
925 projectionError = vpMath::deg(projectionError / (double)nbFeatures);
926 } else {
927 projectionError = 90.0;
928 }
929
930 nbFeaturesForProjErrorComputation = nbFeatures;
931 // std::cout << "Norm Gradient = " << errorGradient << std::endl;
932 }
933
934 /*!
935 Check if the tracking failed.
936
937 \throw vpTrackingException::fatalError if the test fails.
938 */
testTracking()939 void vpMbEdgeTracker::testTracking()
940 {
941 int nbExpectedPoint = 0;
942 int nbGoodPoint = 0;
943 int nbBadPoint = 0;
944
945 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
946 ++it) {
947 vpMbtDistanceLine *l = *it;
948 if (l->isVisible() && l->isTracked()) {
949 for (size_t a = 0; a < l->meline.size(); a++) {
950 if (l->meline[a] != NULL) {
951 nbExpectedPoint += (int)l->meline[a]->expecteddensity;
952 for (std::list<vpMeSite>::const_iterator itme = l->meline[a]->getMeList().begin();
953 itme != l->meline[a]->getMeList().end(); ++itme) {
954 vpMeSite pix = *itme;
955 if (pix.getState() == vpMeSite::NO_SUPPRESSION)
956 nbGoodPoint++;
957 else
958 nbBadPoint++;
959 }
960 }
961 }
962 }
963 }
964
965 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
966 it != cylinders[scaleLevel].end(); ++it) {
967 vpMbtDistanceCylinder *cy = *it;
968 if ((cy->meline1 != NULL && cy->meline2 != NULL) && cy->isVisible() && cy->isTracked()) {
969 nbExpectedPoint += (int)cy->meline1->expecteddensity;
970 for (std::list<vpMeSite>::const_iterator itme1 = cy->meline1->getMeList().begin();
971 itme1 != cy->meline1->getMeList().end(); ++itme1) {
972 vpMeSite pix = *itme1;
973 if (pix.getState() == vpMeSite::NO_SUPPRESSION)
974 nbGoodPoint++;
975 else
976 nbBadPoint++;
977 }
978 nbExpectedPoint += (int)cy->meline2->expecteddensity;
979 for (std::list<vpMeSite>::const_iterator itme2 = cy->meline2->getMeList().begin();
980 itme2 != cy->meline2->getMeList().end(); ++itme2) {
981 vpMeSite pix = *itme2;
982 if (pix.getState() == vpMeSite::NO_SUPPRESSION)
983 nbGoodPoint++;
984 else
985 nbBadPoint++;
986 }
987 }
988 }
989
990 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
991 it != circles[scaleLevel].end(); ++it) {
992 vpMbtDistanceCircle *ci = *it;
993 if (ci->isVisible() && ci->isTracked() && ci->meEllipse != NULL) {
994 nbExpectedPoint += ci->meEllipse->getExpectedDensity();
995 for (std::list<vpMeSite>::const_iterator itme = ci->meEllipse->getMeList().begin();
996 itme != ci->meEllipse->getMeList().end(); ++itme) {
997 vpMeSite pix = *itme;
998 if (pix.getState() == vpMeSite::NO_SUPPRESSION)
999 nbGoodPoint++;
1000 else
1001 nbBadPoint++;
1002 }
1003 }
1004 }
1005
1006 // Compare the number of good points with the min between the number of
1007 // expected points and number of points that are tracked
1008 int nb_min = (int)vpMath::minimum(percentageGdPt * nbExpectedPoint, percentageGdPt * (nbGoodPoint + nbBadPoint));
1009 // int nb_min = (std::min)(val1, val2);
1010 if (nbGoodPoint < nb_min || nbExpectedPoint < 2) {
1011 std::ostringstream oss;
1012 oss << "Not enough moving edges (" << nbGoodPoint << ") to track the object: expected " << nb_min
1013 << ". Try to reduce the threshold=" << percentageGdPt
1014 << " using vpMbTracker::setGoodMovingEdgesRatioThreshold()";
1015 throw vpTrackingException(vpTrackingException::fatalError, oss.str());
1016 }
1017 }
1018
1019 /*!
1020 Compute each state of the tracking procedure for all the feature sets.
1021
1022 If the tracking is considered as failed an exception is thrown.
1023
1024 \param I : The image.
1025 */
track(const vpImage<unsigned char> & I)1026 void vpMbEdgeTracker::track(const vpImage<unsigned char> &I)
1027 {
1028 initPyramid(I, Ipyramid);
1029
1030 unsigned int lvl = (unsigned int)scales.size();
1031 do {
1032 lvl--;
1033
1034 projectionError = 90.0;
1035
1036 if (scales[lvl]) {
1037 vpHomogeneousMatrix cMo_1 = m_cMo;
1038 try {
1039 downScale(lvl);
1040
1041 try {
1042 trackMovingEdge(*Ipyramid[lvl]);
1043 } catch (...) {
1044 vpTRACE("Error in moving edge tracking");
1045 throw;
1046 }
1047
1048 // initialize the vector that contains the error and the matrix that
1049 // contains the interaction matrix AY: Useless as it is done in
1050 // coputeVVS()
1051 /*
1052 for(std::list<vpMbtDistanceLine*>::const_iterator
1053 it=lines[lvl].begin(); it!=lines[lvl].end(); ++it){ l = *it; if
1054 (l->isVisible()){ l->initInteractionMatrixError();
1055 }
1056 }
1057
1058 for(std::list<vpMbtDistanceCylinder*>::const_iterator
1059 it=cylinders[lvl].begin(); it!=cylinders[lvl].end(); ++it){ cy = *it;
1060 if(cy->isVisible()) {
1061 cy->initInteractionMatrixError();
1062 }
1063 }
1064
1065 for(std::list<vpMbtDistanceCircle*>::const_iterator
1066 it=circles[lvl].begin(); it!=circles[lvl].end(); ++it){ ci = *it; if
1067 (ci->isVisible()){ ci->initInteractionMatrixError();
1068 }
1069 }
1070 */
1071
1072 try {
1073 computeVVS(*Ipyramid[lvl], lvl);
1074 } catch (...) {
1075 covarianceMatrix = -1;
1076 throw; // throw the original exception
1077 }
1078
1079 testTracking();
1080
1081 if (displayFeatures) {
1082 m_featuresToBeDisplayedEdge = getFeaturesForDisplayEdge();
1083 }
1084
1085 // Looking for new visible face
1086 bool newvisibleface = false;
1087 visibleFace(I, m_cMo, newvisibleface);
1088
1089 // cam.computeFov(I.getWidth(), I.getHeight());
1090 if (useScanLine) {
1091 faces.computeClippedPolygons(m_cMo, m_cam);
1092 faces.computeScanLineRender(m_cam, I.getWidth(), I.getHeight());
1093 }
1094
1095 updateMovingEdge(I);
1096
1097 initMovingEdge(I, m_cMo);
1098 // Reinit the moving edge for the lines which need it.
1099 reinitMovingEdge(I, m_cMo);
1100
1101 if (computeProjError)
1102 computeProjectionError(I);
1103
1104 upScale(lvl);
1105 } catch (const vpException &e) {
1106 if (lvl != 0) {
1107 m_cMo = cMo_1;
1108 reInitLevel(lvl);
1109 upScale(lvl);
1110 } else {
1111 upScale(lvl);
1112 throw(e);
1113 }
1114 }
1115 }
1116 } while (lvl != 0);
1117
1118 cleanPyramid(Ipyramid);
1119 }
1120
track(const vpImage<vpRGBa> & I)1121 void vpMbEdgeTracker::track(const vpImage<vpRGBa> &I)
1122 {
1123 vpImageConvert::convert(I, m_I);
1124 track(m_I);
1125 }
1126
1127 /*!
1128 Initialize the tracking.
1129
1130 \param I : The image.
1131 */
init(const vpImage<unsigned char> & I)1132 void vpMbEdgeTracker::init(const vpImage<unsigned char> &I)
1133 {
1134 if (!modelInitialised) {
1135 throw vpException(vpException::fatalError, "model not initialized");
1136 }
1137
1138 bool a = false;
1139
1140 #ifdef VISP_HAVE_OGRE
1141 if (useOgre) {
1142 if (!faces.isOgreInitialised()) {
1143 faces.setBackgroundSizeOgre(I.getHeight(), I.getWidth());
1144 faces.setOgreShowConfigDialog(ogreShowConfigDialog);
1145 faces.initOgre(m_cam);
1146 // Turn off Ogre config dialog display for the next call to this
1147 // function since settings are saved in the ogre.cfg file and used
1148 // during the next call
1149 ogreShowConfigDialog = false;
1150 }
1151 }
1152 #endif
1153
1154 if (clippingFlag > 2)
1155 m_cam.computeFov(I.getWidth(), I.getHeight());
1156
1157 visibleFace(I, m_cMo, a);
1158 resetMovingEdge();
1159
1160 if (useScanLine) {
1161 if (clippingFlag <= 2)
1162 m_cam.computeFov(I.getWidth(), I.getHeight());
1163
1164 faces.computeClippedPolygons(m_cMo, m_cam);
1165 faces.computeScanLineRender(m_cam, I.getWidth(), I.getHeight());
1166 }
1167
1168 initPyramid(I, Ipyramid);
1169 unsigned int i = (unsigned int)scales.size();
1170 do {
1171 i--;
1172 if (scales[i]) {
1173 downScale(i);
1174 initMovingEdge(*Ipyramid[i], m_cMo);
1175 upScale(i);
1176 }
1177 } while (i != 0);
1178
1179 cleanPyramid(Ipyramid);
1180 }
1181
1182 /*!
1183 Set the pose to be used in entry of the next call to the track() function.
1184 This pose will be just used once.
1185
1186 \param I : grayscale image corresponding to the desired pose.
1187 \param cdMo : Pose to affect.
1188 */
setPose(const vpImage<unsigned char> & I,const vpHomogeneousMatrix & cdMo)1189 void vpMbEdgeTracker::setPose(const vpImage<unsigned char> &I, const vpHomogeneousMatrix &cdMo)
1190 {
1191 m_cMo = cdMo;
1192
1193 init(I);
1194 }
1195
1196 /*!
1197 Set the pose to be used in entry of the next call to the track() function.
1198 This pose will be just used once.
1199
1200 \param I_color : color image corresponding to the desired pose.
1201 \param cdMo : Pose to affect.
1202 */
setPose(const vpImage<vpRGBa> & I_color,const vpHomogeneousMatrix & cdMo)1203 void vpMbEdgeTracker::setPose(const vpImage<vpRGBa> &I_color, const vpHomogeneousMatrix &cdMo)
1204 {
1205 m_cMo = cdMo;
1206
1207 vpImageConvert::convert(I_color, m_I);
1208 init(m_I);
1209 }
1210
1211 /*!
1212 Load the xml configuration file.
1213 From the configuration file
1214 initialize the parameters corresponding to the objects: moving-edges, camera
1215 and visibility angles.
1216
1217 \param configFile : full name of the xml file.
1218 \param verbose : verbose flag.
1219
1220 \sa loadConfigFile(const char*)
1221 */
loadConfigFile(const std::string & configFile,bool verbose)1222 void vpMbEdgeTracker::loadConfigFile(const std::string &configFile, bool verbose)
1223 {
1224 // Load projection error config
1225 vpMbTracker::loadConfigFile(configFile, verbose);
1226
1227 vpMbtXmlGenericParser xmlp(vpMbtXmlGenericParser::EDGE_PARSER);
1228 xmlp.setVerbose(verbose);
1229 xmlp.setCameraParameters(m_cam);
1230 xmlp.setAngleAppear(vpMath::deg(angleAppears));
1231 xmlp.setAngleDisappear(vpMath::deg(angleDisappears));
1232 xmlp.setEdgeMe(me);
1233
1234 try {
1235 if (verbose) {
1236 std::cout << " *********** Parsing XML for Mb Edge Tracker ************ " << std::endl;
1237 }
1238 xmlp.parse(configFile);
1239 } catch (...) {
1240 throw vpException(vpException::ioError, "Cannot open XML file \"%s\"", configFile.c_str());
1241 }
1242
1243 vpCameraParameters camera;
1244 vpMe meParser;
1245 xmlp.getCameraParameters(camera);
1246 xmlp.getEdgeMe(meParser);
1247
1248 setCameraParameters(camera);
1249 setMovingEdge(meParser);
1250 angleAppears = vpMath::rad(xmlp.getAngleAppear());
1251 angleDisappears = vpMath::rad(xmlp.getAngleDisappear());
1252
1253 if (xmlp.hasNearClippingDistance())
1254 setNearClippingDistance(xmlp.getNearClippingDistance());
1255
1256 if (xmlp.hasFarClippingDistance())
1257 setFarClippingDistance(xmlp.getFarClippingDistance());
1258
1259 if (xmlp.getFovClipping())
1260 setClipping(clippingFlag | vpPolygon3D::FOV_CLIPPING);
1261
1262 useLodGeneral = xmlp.getLodState();
1263 minLineLengthThresholdGeneral = xmlp.getLodMinLineLengthThreshold();
1264 minPolygonAreaThresholdGeneral = xmlp.getLodMinPolygonAreaThreshold();
1265
1266 applyLodSettingInConfig = false;
1267 if (this->getNbPolygon() > 0) {
1268 applyLodSettingInConfig = true;
1269 setLod(useLodGeneral);
1270 setMinLineLengthThresh(minLineLengthThresholdGeneral);
1271 setMinPolygonAreaThresh(minPolygonAreaThresholdGeneral);
1272 }
1273 }
1274
1275 /*!
1276 Display the 3D model from a given position of the camera.
1277
1278 \param I : The image.
1279 \param cMo : Pose used to project the 3D model into the image.
1280 \param cam : The camera parameters.
1281 \param col : The desired color.
1282 \param thickness : The thickness of the lines.
1283 \param displayFullModel : If true, the full model is displayed (even the non
1284 visible faces).
1285 */
display(const vpImage<unsigned char> & I,const vpHomogeneousMatrix & cMo,const vpCameraParameters & cam,const vpColor & col,unsigned int thickness,bool displayFullModel)1286 void vpMbEdgeTracker::display(const vpImage<unsigned char> &I, const vpHomogeneousMatrix &cMo,
1287 const vpCameraParameters &cam, const vpColor &col, unsigned int thickness,
1288 bool displayFullModel)
1289 {
1290 //Display first the Moving-Edges
1291 if (displayFeatures) {
1292 displayFeaturesOnImage(I);
1293 }
1294
1295 std::vector<std::vector<double> > models = vpMbEdgeTracker::getModelForDisplay(I.getWidth(), I.getHeight(), cMo, cam, displayFullModel);
1296
1297 for (size_t i = 0; i < models.size(); i++) {
1298 if (vpMath::equal(models[i][0], 0)) {
1299 vpImagePoint ip1(models[i][1], models[i][2]);
1300 vpImagePoint ip2(models[i][3], models[i][4]);
1301 vpDisplay::displayLine(I, ip1, ip2, col, thickness);
1302 } else if (vpMath::equal(models[i][0], 1)) {
1303 vpImagePoint center(models[i][1], models[i][2]);
1304 double n20 = models[i][3];
1305 double n11 = models[i][4];
1306 double n02 = models[i][5];
1307 vpDisplay::displayEllipse(I, center, n20, n11, n02, true, col, thickness);
1308 }
1309 }
1310
1311 #ifdef VISP_HAVE_OGRE
1312 if (useOgre)
1313 faces.displayOgre(cMo);
1314 #endif
1315 }
1316
1317 /*!
1318 Display the 3D model from a given position of the camera.
1319
1320 \param I : The image.
1321 \param cMo : Pose used to project the 3D model into the image.
1322 \param cam : The camera parameters.
1323 \param col : The desired color.
1324 \param thickness : The thickness of the lines.
1325 \param displayFullModel : If true, the full model is displayed (even the non
1326 visible surfaces).
1327 */
display(const vpImage<vpRGBa> & I,const vpHomogeneousMatrix & cMo,const vpCameraParameters & cam,const vpColor & col,unsigned int thickness,bool displayFullModel)1328 void vpMbEdgeTracker::display(const vpImage<vpRGBa> &I, const vpHomogeneousMatrix &cMo,
1329 const vpCameraParameters &cam, const vpColor &col, unsigned int thickness,
1330 bool displayFullModel)
1331 {
1332 //Display first the Moving-Edges
1333 if (displayFeatures) {
1334 displayFeaturesOnImage(I);
1335 }
1336
1337 std::vector<std::vector<double> > models = vpMbEdgeTracker::getModelForDisplay(I.getWidth(), I.getHeight(), cMo, cam, displayFullModel);
1338
1339 for (size_t i = 0; i < models.size(); i++) {
1340 if (vpMath::equal(models[i][0], 0)) {
1341 vpImagePoint ip1(models[i][1], models[i][2]);
1342 vpImagePoint ip2(models[i][3], models[i][4]);
1343 vpDisplay::displayLine(I, ip1, ip2, col, thickness);
1344 } else if (vpMath::equal(models[i][0], 1)) {
1345 vpImagePoint center(models[i][1], models[i][2]);
1346 double n20 = models[i][3];
1347 double n11 = models[i][4];
1348 double n02 = models[i][5];
1349 vpDisplay::displayEllipse(I, center, n20, n11, n02, true, col, thickness);
1350 }
1351 }
1352
1353 #ifdef VISP_HAVE_OGRE
1354 if (useOgre)
1355 faces.displayOgre(cMo);
1356 #endif
1357 }
1358
getFeaturesForDisplayEdge()1359 std::vector<std::vector<double> > vpMbEdgeTracker::getFeaturesForDisplayEdge()
1360 {
1361 std::vector<std::vector<double> > features;
1362
1363 const unsigned int lvl = 0;
1364 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[lvl].begin(); it != lines[lvl].end(); ++it) {
1365 vpMbtDistanceLine *l = *it;
1366 if (l->isVisible() && l->isTracked()) {
1367 std::vector<std::vector<double> > currentFeatures = l->getFeaturesForDisplay();
1368 features.insert(features.end(), currentFeatures.begin(), currentFeatures.end());
1369 }
1370 }
1371
1372 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[lvl].begin(); it != cylinders[lvl].end();
1373 ++it) {
1374 vpMbtDistanceCylinder *cy = *it;
1375 if (cy->isVisible() && cy->isTracked()) {
1376 std::vector<std::vector<double> > currentFeatures = cy->getFeaturesForDisplay();
1377 features.insert(features.end(), currentFeatures.begin(), currentFeatures.end());
1378 }
1379 }
1380
1381 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[lvl].begin(); it != circles[lvl].end(); ++it) {
1382 vpMbtDistanceCircle *ci = *it;
1383 if (ci->isVisible() && ci->isTracked()) {
1384 std::vector<std::vector<double> > currentFeatures = ci->getFeaturesForDisplay();
1385 features.insert(features.end(), currentFeatures.begin(), currentFeatures.end());
1386 }
1387 }
1388
1389 return features;
1390 }
1391
1392 /*!
1393 Return a list of primitives parameters to display the model at a given pose and camera parameters.
1394 - Line parameters are: `<primitive id (here 0 for line)>`, `<pt_start.i()>`, `<pt_start.j()>`,
1395 `<pt_end.i()>`, `<pt_end.j()>`
1396 - Ellipse parameters are: `<primitive id (here 1 for ellipse)>`, `<pt_center.i()>`, `<pt_center.j()>`,
1397 `<n_20>`, `<n_11>`, `<n_02>` where `<n_ij>` are the second order centered moments of the ellipse
1398 normalized by its area (i.e., such that \f$n_{ij} = \mu_{ij}/a\f$ where \f$\mu_{ij}\f$ are the centered moments and a the area).
1399
1400 \param width : Image width.
1401 \param height : Image height.
1402 \param cMo : Pose used to project the 3D model into the image.
1403 \param cam : The camera parameters.
1404 \param displayFullModel : If true, the line is displayed even if it is not
1405 */
getModelForDisplay(unsigned int width,unsigned int height,const vpHomogeneousMatrix & cMo,const vpCameraParameters & cam,bool displayFullModel)1406 std::vector<std::vector<double> > vpMbEdgeTracker::getModelForDisplay(unsigned int width, unsigned int height,
1407 const vpHomogeneousMatrix &cMo,
1408 const vpCameraParameters &cam,
1409 bool displayFullModel)
1410 {
1411 std::vector<std::vector<double> > models;
1412
1413 for (unsigned int i = 0; i < scales.size(); i += 1) {
1414 if (scales[i]) {
1415 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
1416 ++it) {
1417 std::vector<std::vector<double> > currentModel =
1418 (*it)->getModelForDisplay(width, height, cMo, cam, displayFullModel);
1419 models.insert(models.end(), currentModel.begin(), currentModel.end());
1420 }
1421
1422 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
1423 it != cylinders[scaleLevel].end(); ++it) {
1424 std::vector<std::vector<double> > currentModel =
1425 (*it)->getModelForDisplay(width, height, cMo, cam, displayFullModel);
1426 models.insert(models.end(), currentModel.begin(), currentModel.end());
1427 }
1428
1429 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
1430 it != circles[scaleLevel].end(); ++it) {
1431 std::vector<double> paramsCircle = (*it)->getModelForDisplay(cMo, cam, displayFullModel);
1432 if (!paramsCircle.empty()) {
1433 models.push_back(paramsCircle);
1434 }
1435 }
1436 break; // displaying model on one scale only
1437 }
1438 }
1439
1440 return models;
1441 }
1442
displayFeaturesOnImage(const vpImage<unsigned char> & I)1443 void vpMbEdgeTracker::displayFeaturesOnImage(const vpImage<unsigned char> &I)
1444 {
1445 for (size_t i = 0; i < m_featuresToBeDisplayedEdge.size(); i++) {
1446 if (vpMath::equal(m_featuresToBeDisplayedEdge[i][0], 0)) {
1447 vpImagePoint ip(m_featuresToBeDisplayedEdge[i][1], m_featuresToBeDisplayedEdge[i][2]);
1448 int state = static_cast<int>(m_featuresToBeDisplayedEdge[i][3]);
1449
1450 switch (state) {
1451 case vpMeSite::NO_SUPPRESSION:
1452 vpDisplay::displayCross(I, ip, 3, vpColor::green, 1);
1453 break;
1454
1455 case vpMeSite::CONSTRAST:
1456 vpDisplay::displayCross(I, ip, 3, vpColor::blue, 1);
1457 break;
1458
1459 case vpMeSite::THRESHOLD:
1460 vpDisplay::displayCross(I, ip, 3, vpColor::purple, 1);
1461 break;
1462
1463 case vpMeSite::M_ESTIMATOR:
1464 vpDisplay::displayCross(I, ip, 3, vpColor::red, 1);
1465 break;
1466
1467 case vpMeSite::TOO_NEAR:
1468 vpDisplay::displayCross(I, ip, 3, vpColor::cyan, 1);
1469 break;
1470
1471 default:
1472 vpDisplay::displayCross(I, ip, 3, vpColor::yellow, 1);
1473 }
1474 }
1475 }
1476 }
1477
displayFeaturesOnImage(const vpImage<vpRGBa> & I)1478 void vpMbEdgeTracker::displayFeaturesOnImage(const vpImage<vpRGBa> &I)
1479 {
1480 for (size_t i = 0; i < m_featuresToBeDisplayedEdge.size(); i++) {
1481 if (vpMath::equal(m_featuresToBeDisplayedEdge[i][0], 0)) {
1482 vpImagePoint ip(m_featuresToBeDisplayedEdge[i][1], m_featuresToBeDisplayedEdge[i][2]);
1483 int state = static_cast<int>(m_featuresToBeDisplayedEdge[i][3]);
1484
1485 switch (state) {
1486 case vpMeSite::NO_SUPPRESSION:
1487 vpDisplay::displayCross(I, ip, 3, vpColor::green, 1);
1488 break;
1489
1490 case vpMeSite::CONSTRAST:
1491 vpDisplay::displayCross(I, ip, 3, vpColor::blue, 1);
1492 break;
1493
1494 case vpMeSite::THRESHOLD:
1495 vpDisplay::displayCross(I, ip, 3, vpColor::purple, 1);
1496 break;
1497
1498 case vpMeSite::M_ESTIMATOR:
1499 vpDisplay::displayCross(I, ip, 3, vpColor::red, 1);
1500 break;
1501
1502 case vpMeSite::TOO_NEAR:
1503 vpDisplay::displayCross(I, ip, 3, vpColor::cyan, 1);
1504 break;
1505
1506 default:
1507 vpDisplay::displayCross(I, ip, 3, vpColor::yellow, 1);
1508 }
1509 }
1510 }
1511 }
1512
1513 /*!
1514 Initialize the moving edge thanks to a given pose of the camera.
1515 The 3D model is projected into the image to create moving edges along the
1516 lines.
1517
1518 \param I : The image.
1519 \param _cMo : The pose of the camera used to initialize the moving edges.
1520 */
initMovingEdge(const vpImage<unsigned char> & I,const vpHomogeneousMatrix & _cMo)1521 void vpMbEdgeTracker::initMovingEdge(const vpImage<unsigned char> &I, const vpHomogeneousMatrix &_cMo)
1522 {
1523 const bool doNotTrack = false;
1524
1525 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
1526 ++it) {
1527 vpMbtDistanceLine *l = *it;
1528 bool isvisible = false;
1529
1530 for (std::list<int>::const_iterator itindex = l->Lindex_polygon.begin(); itindex != l->Lindex_polygon.end();
1531 ++itindex) {
1532 int index = *itindex;
1533 if (index == -1)
1534 isvisible = true;
1535 else {
1536 if (l->hiddenface->isVisible((unsigned int)index))
1537 isvisible = true;
1538 }
1539 }
1540
1541 // Si la ligne n'appartient a aucune face elle est tout le temps visible
1542 if (l->Lindex_polygon.empty())
1543 isvisible = true; // Not sure that this can occur
1544
1545 if (isvisible) {
1546 l->setVisible(true);
1547 l->updateTracked();
1548 if (l->meline.empty() && l->isTracked())
1549 l->initMovingEdge(I, _cMo, doNotTrack, m_mask);
1550 } else {
1551 l->setVisible(false);
1552 for (size_t a = 0; a < l->meline.size(); a++) {
1553 if (l->meline[a] != NULL)
1554 delete l->meline[a];
1555 if (a < l->nbFeature.size())
1556 l->nbFeature[a] = 0;
1557 }
1558 l->nbFeatureTotal = 0;
1559 l->meline.clear();
1560 l->nbFeature.clear();
1561 }
1562 }
1563
1564 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
1565 it != cylinders[scaleLevel].end(); ++it) {
1566 vpMbtDistanceCylinder *cy = *it;
1567
1568 bool isvisible = false;
1569
1570 int index = cy->index_polygon;
1571 if (index == -1)
1572 isvisible = true;
1573 else {
1574 if (cy->hiddenface->isVisible((unsigned int)index + 1) || cy->hiddenface->isVisible((unsigned int)index + 2) ||
1575 cy->hiddenface->isVisible((unsigned int)index + 3) || cy->hiddenface->isVisible((unsigned int)index + 4))
1576 isvisible = true;
1577 }
1578 // vpTRACE("cyl with index %d is visible: %d", index, isvisible);
1579
1580 if (isvisible) {
1581 cy->setVisible(true);
1582 if (cy->meline1 == NULL || cy->meline2 == NULL) {
1583 if (cy->isTracked())
1584 cy->initMovingEdge(I, _cMo, doNotTrack, m_mask);
1585 }
1586 } else {
1587 cy->setVisible(false);
1588 if (cy->meline1 != NULL)
1589 delete cy->meline1;
1590 if (cy->meline2 != NULL)
1591 delete cy->meline2;
1592 cy->meline1 = NULL;
1593 cy->meline2 = NULL;
1594 cy->nbFeature = 0;
1595 cy->nbFeaturel1 = 0;
1596 cy->nbFeaturel2 = 0;
1597 }
1598 }
1599
1600 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
1601 it != circles[scaleLevel].end(); ++it) {
1602 vpMbtDistanceCircle *ci = *it;
1603 bool isvisible = false;
1604
1605 int index = ci->index_polygon;
1606 if (index == -1)
1607 isvisible = true;
1608 else {
1609 if (ci->hiddenface->isVisible((unsigned int)index))
1610 isvisible = true;
1611 }
1612
1613 if (isvisible) {
1614 ci->setVisible(true);
1615 if (ci->meEllipse == NULL) {
1616 if (ci->isTracked())
1617 ci->initMovingEdge(I, _cMo, doNotTrack, m_mask);
1618 }
1619 } else {
1620 ci->setVisible(false);
1621 if (ci->meEllipse != NULL)
1622 delete ci->meEllipse;
1623 ci->meEllipse = NULL;
1624 ci->nbFeature = 0;
1625 }
1626 }
1627 }
1628
1629 /*!
1630 Track the moving edges in the image.
1631
1632 \param I : the image.
1633 */
trackMovingEdge(const vpImage<unsigned char> & I)1634 void vpMbEdgeTracker::trackMovingEdge(const vpImage<unsigned char> &I)
1635 {
1636 const bool doNotTrack = false;
1637
1638 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
1639 ++it) {
1640 vpMbtDistanceLine *l = *it;
1641 if (l->isVisible() && l->isTracked()) {
1642 if (l->meline.empty()) {
1643 l->initMovingEdge(I, m_cMo, doNotTrack, m_mask);
1644 }
1645 l->trackMovingEdge(I);
1646 }
1647 }
1648
1649 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
1650 it != cylinders[scaleLevel].end(); ++it) {
1651 vpMbtDistanceCylinder *cy = *it;
1652 if (cy->isVisible() && cy->isTracked()) {
1653 if (cy->meline1 == NULL || cy->meline2 == NULL) {
1654 cy->initMovingEdge(I, m_cMo, doNotTrack, m_mask);
1655 }
1656 cy->trackMovingEdge(I, m_cMo);
1657 }
1658 }
1659
1660 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
1661 it != circles[scaleLevel].end(); ++it) {
1662 vpMbtDistanceCircle *ci = *it;
1663 if (ci->isVisible() && ci->isTracked()) {
1664 if (ci->meEllipse == NULL) {
1665 ci->initMovingEdge(I, m_cMo, doNotTrack, m_mask);
1666 }
1667 ci->trackMovingEdge(I, m_cMo);
1668 }
1669 }
1670 }
1671
1672 /*!
1673 Update the moving edges at the end of the virtual visual servoing.
1674
1675 \param I : the image.
1676 */
updateMovingEdge(const vpImage<unsigned char> & I)1677 void vpMbEdgeTracker::updateMovingEdge(const vpImage<unsigned char> &I)
1678 {
1679 vpMbtDistanceLine *l;
1680 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
1681 ++it) {
1682 if ((*it)->isTracked()) {
1683 l = *it;
1684 l->updateMovingEdge(I, m_cMo);
1685 if (l->nbFeatureTotal == 0 && l->isVisible()) {
1686 l->Reinit = true;
1687 }
1688 }
1689 }
1690
1691 vpMbtDistanceCylinder *cy;
1692 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
1693 it != cylinders[scaleLevel].end(); ++it) {
1694 if ((*it)->isTracked()) {
1695 cy = *it;
1696 cy->updateMovingEdge(I, m_cMo);
1697 if ((cy->nbFeaturel1 == 0 || cy->nbFeaturel2 == 0) && cy->isVisible()) {
1698 cy->Reinit = true;
1699 }
1700 }
1701 }
1702
1703 vpMbtDistanceCircle *ci;
1704 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
1705 it != circles[scaleLevel].end(); ++it) {
1706 if ((*it)->isTracked()) {
1707 ci = *it;
1708 ci->updateMovingEdge(I, m_cMo);
1709 if (ci->nbFeature == 0 && ci->isVisible()) {
1710 ci->Reinit = true;
1711 }
1712 }
1713 }
1714 }
1715
updateMovingEdgeWeights()1716 void vpMbEdgeTracker::updateMovingEdgeWeights()
1717 {
1718 unsigned int n = 0;
1719
1720 vpMbtDistanceLine *l;
1721 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
1722 ++it) {
1723 if ((*it)->isTracked()) {
1724 l = *it;
1725 unsigned int indexLine = 0;
1726 double wmean = 0;
1727 for (size_t a = 0; a < l->meline.size(); a++) {
1728 if (l->nbFeature[a] > 0) {
1729 std::list<vpMeSite>::iterator itListLine;
1730 itListLine = l->meline[a]->getMeList().begin();
1731
1732 for (unsigned int i = 0; i < l->nbFeature[a]; i++) {
1733 wmean += m_w_edge[n + indexLine];
1734 vpMeSite p = *itListLine;
1735 if (m_w_edge[n + indexLine] < 0.5) {
1736 p.setState(vpMeSite::M_ESTIMATOR);
1737
1738 *itListLine = p;
1739 }
1740
1741 ++itListLine;
1742 indexLine++;
1743 }
1744 }
1745 }
1746 n += l->nbFeatureTotal;
1747
1748 if (l->nbFeatureTotal != 0)
1749 wmean /= l->nbFeatureTotal;
1750 else
1751 wmean = 1;
1752
1753 l->setMeanWeight(wmean);
1754
1755 if (wmean < 0.8)
1756 l->Reinit = true;
1757 }
1758 }
1759
1760 // Same thing with cylinders as with lines
1761 vpMbtDistanceCylinder *cy;
1762 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
1763 it != cylinders[scaleLevel].end(); ++it) {
1764 if ((*it)->isTracked()) {
1765 cy = *it;
1766 double wmean = 0;
1767 std::list<vpMeSite>::iterator itListCyl1;
1768 std::list<vpMeSite>::iterator itListCyl2;
1769
1770 if (cy->nbFeature > 0) {
1771 itListCyl1 = cy->meline1->getMeList().begin();
1772 itListCyl2 = cy->meline2->getMeList().begin();
1773
1774 for (unsigned int i = 0; i < cy->nbFeaturel1; i++) {
1775 wmean += m_w_edge[n + i];
1776 vpMeSite p = *itListCyl1;
1777 if (m_w_edge[n + i] < 0.5) {
1778 p.setState(vpMeSite::M_ESTIMATOR);
1779
1780 *itListCyl1 = p;
1781 }
1782
1783 ++itListCyl1;
1784 }
1785 }
1786
1787 if (cy->nbFeaturel1 != 0)
1788 wmean /= cy->nbFeaturel1;
1789 else
1790 wmean = 1;
1791
1792 cy->setMeanWeight1(wmean);
1793
1794 if (wmean < 0.8) {
1795 cy->Reinit = true;
1796 }
1797
1798 wmean = 0;
1799 for (unsigned int i = cy->nbFeaturel1; i < cy->nbFeature; i++) {
1800 wmean += m_w_edge[n + i];
1801 vpMeSite p = *itListCyl2;
1802 if (m_w_edge[n + i] < 0.5) {
1803 p.setState(vpMeSite::M_ESTIMATOR);
1804
1805 *itListCyl2 = p;
1806 }
1807
1808 ++itListCyl2;
1809 }
1810
1811 if (cy->nbFeaturel2 != 0)
1812 wmean /= cy->nbFeaturel2;
1813 else
1814 wmean = 1;
1815
1816 cy->setMeanWeight2(wmean);
1817
1818 if (wmean < 0.8) {
1819 cy->Reinit = true;
1820 }
1821
1822 n += cy->nbFeature;
1823 }
1824 }
1825
1826 // Same thing with circles as with lines
1827 vpMbtDistanceCircle *ci;
1828 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
1829 it != circles[scaleLevel].end(); ++it) {
1830 if ((*it)->isTracked()) {
1831 ci = *it;
1832 double wmean = 0;
1833 std::list<vpMeSite>::iterator itListCir;
1834
1835 if (ci->nbFeature > 0) {
1836 itListCir = ci->meEllipse->getMeList().begin();
1837 }
1838
1839 wmean = 0;
1840 for (unsigned int i = 0; i < ci->nbFeature; i++) {
1841 wmean += m_w_edge[n + i];
1842 vpMeSite p = *itListCir;
1843 if (m_w_edge[n + i] < 0.5) {
1844 p.setState(vpMeSite::M_ESTIMATOR);
1845
1846 *itListCir = p;
1847 }
1848
1849 ++itListCir;
1850 }
1851
1852 if (ci->nbFeature != 0)
1853 wmean /= ci->nbFeature;
1854 else
1855 wmean = 1;
1856
1857 ci->setMeanWeight(wmean);
1858
1859 if (wmean < 0.8) {
1860 ci->Reinit = true;
1861 }
1862
1863 n += ci->nbFeature;
1864 }
1865 }
1866 }
1867
1868 /*!
1869 Reinitialize the lines if it is required.
1870
1871 A line is reinitialized if the 2D line do not match enough with the
1872 projected 3D line.
1873
1874 \param I : the image.
1875 \param _cMo : the pose of the used to re-initialize the moving edges
1876 */
reinitMovingEdge(const vpImage<unsigned char> & I,const vpHomogeneousMatrix & _cMo)1877 void vpMbEdgeTracker::reinitMovingEdge(const vpImage<unsigned char> &I, const vpHomogeneousMatrix &_cMo)
1878 {
1879 vpMbtDistanceLine *l;
1880 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
1881 ++it) {
1882 if ((*it)->isTracked()) {
1883 l = *it;
1884 if (l->Reinit && l->isVisible())
1885 l->reinitMovingEdge(I, _cMo, m_mask);
1886 }
1887 }
1888
1889 vpMbtDistanceCylinder *cy;
1890 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
1891 it != cylinders[scaleLevel].end(); ++it) {
1892 if ((*it)->isTracked()) {
1893 cy = *it;
1894 if (cy->Reinit && cy->isVisible())
1895 cy->reinitMovingEdge(I, _cMo, m_mask);
1896 }
1897 }
1898
1899 vpMbtDistanceCircle *ci;
1900 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
1901 it != circles[scaleLevel].end(); ++it) {
1902 if ((*it)->isTracked()) {
1903 ci = *it;
1904 if (ci->Reinit && ci->isVisible())
1905 ci->reinitMovingEdge(I, _cMo, m_mask);
1906 }
1907 }
1908 }
1909
resetMovingEdge()1910 void vpMbEdgeTracker::resetMovingEdge()
1911 {
1912 // Clear ME to be displayed
1913 m_featuresToBeDisplayedEdge.clear();
1914
1915 for (unsigned int i = 0; i < scales.size(); i += 1) {
1916 if (scales[i]) {
1917 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
1918 for (size_t a = 0; a < (*it)->meline.size(); a++) {
1919 if ((*it)->meline[a] != NULL) {
1920 delete (*it)->meline[a];
1921 (*it)->meline[a] = NULL;
1922 }
1923 }
1924
1925 (*it)->meline.clear();
1926 (*it)->nbFeature.clear();
1927 (*it)->nbFeatureTotal = 0;
1928 }
1929
1930 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[i].begin(); it != cylinders[i].end();
1931 ++it) {
1932 if ((*it)->meline1 != NULL) {
1933 delete (*it)->meline1;
1934 (*it)->meline1 = NULL;
1935 }
1936 if ((*it)->meline2 != NULL) {
1937 delete (*it)->meline2;
1938 (*it)->meline2 = NULL;
1939 }
1940
1941 (*it)->nbFeature = 0;
1942 (*it)->nbFeaturel1 = 0;
1943 (*it)->nbFeaturel2 = 0;
1944 }
1945
1946 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
1947 if ((*it)->meEllipse != NULL) {
1948 delete (*it)->meEllipse;
1949 (*it)->meEllipse = NULL;
1950 }
1951 (*it)->nbFeature = 0;
1952 }
1953 }
1954 }
1955 }
1956
1957 /*!
1958 Add a line belonging to the \f$ index \f$ the polygon to the list of lines.
1959 It is defined by its two extremities.
1960
1961 If the line already exists, the ploygone's index is added to the list of
1962 polygon to which it belongs.
1963
1964 \param P1 : The first extremity of the line.
1965 \param P2 : The second extremity of the line.
1966 \param polygon : The index of the polygon to which the line belongs.
1967 \param name : the optional name of the line
1968 */
addLine(vpPoint & P1,vpPoint & P2,int polygon,std::string name)1969 void vpMbEdgeTracker::addLine(vpPoint &P1, vpPoint &P2, int polygon, std::string name)
1970 {
1971 {
1972 // suppress line already in the model
1973 bool already_here = false;
1974 vpMbtDistanceLine *l;
1975
1976 for (unsigned int i = 0; i < scales.size(); i += 1) {
1977 if (scales[i]) {
1978 downScale(i);
1979 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
1980 l = *it;
1981 if ((samePoint(*(l->p1), P1) && samePoint(*(l->p2), P2)) ||
1982 (samePoint(*(l->p1), P2) && samePoint(*(l->p2), P1))) {
1983 already_here = true;
1984 l->addPolygon(polygon);
1985 l->hiddenface = &faces;
1986 }
1987 }
1988
1989 if (!already_here) {
1990 l = new vpMbtDistanceLine;
1991
1992 l->setCameraParameters(m_cam);
1993 l->buildFrom(P1, P2, m_rand);
1994 l->addPolygon(polygon);
1995 l->setMovingEdge(&me);
1996 l->hiddenface = &faces;
1997 l->useScanLine = useScanLine;
1998
1999 l->setIndex(nline);
2000 l->setName(name);
2001
2002 if (clippingFlag != vpPolygon3D::NO_CLIPPING)
2003 l->getPolygon().setClipping(clippingFlag);
2004
2005 if ((clippingFlag & vpPolygon3D::NEAR_CLIPPING) == vpPolygon3D::NEAR_CLIPPING)
2006 l->getPolygon().setNearClippingDistance(distNearClip);
2007
2008 if ((clippingFlag & vpPolygon3D::FAR_CLIPPING) == vpPolygon3D::FAR_CLIPPING)
2009 l->getPolygon().setFarClippingDistance(distFarClip);
2010
2011 nline += 1;
2012 lines[i].push_back(l);
2013 }
2014 upScale(i);
2015 }
2016 }
2017 }
2018 }
2019
2020 /*!
2021 Remove a line using its name.
2022
2023 \param name : The name of the line to remove.
2024 */
removeLine(const std::string & name)2025 void vpMbEdgeTracker::removeLine(const std::string &name)
2026 {
2027 vpMbtDistanceLine *l;
2028
2029 for (unsigned int i = 0; i < scales.size(); i++) {
2030 if (scales[i]) {
2031 for (std::list<vpMbtDistanceLine *>::iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
2032 l = *it;
2033 if (name.compare(l->getName()) == 0) {
2034 lines[i].erase(it);
2035 break;
2036 }
2037 }
2038 }
2039 }
2040 }
2041
2042 /*!
2043 Add a circle to the list of circles.
2044
2045 \param P1 : Center of the circle.
2046 \param P2,P3 : Two points on the plane containing the circle. With the
2047 center of the circle we have 3 points defining the plane that contains the
2048 circle. \param r : Radius of the circle. \param idFace : Id of the face that
2049 is associated to the circle to handle visibility test. \param name : the
2050 optional name of the circle.
2051 */
addCircle(const vpPoint & P1,const vpPoint & P2,const vpPoint & P3,double r,int idFace,const std::string & name)2052 void vpMbEdgeTracker::addCircle(const vpPoint &P1, const vpPoint &P2, const vpPoint &P3, double r, int idFace,
2053 const std::string &name)
2054 {
2055 {
2056 bool already_here = false;
2057 vpMbtDistanceCircle *ci;
2058
2059 for (unsigned int i = 0; i < scales.size(); i += 1) {
2060 if (scales[i]) {
2061 downScale(i);
2062 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
2063 ci = *it;
2064 if ((samePoint(*(ci->p1), P1) && samePoint(*(ci->p2), P2) && samePoint(*(ci->p3), P3)) ||
2065 (samePoint(*(ci->p1), P1) && samePoint(*(ci->p2), P3) && samePoint(*(ci->p3), P2))) {
2066 already_here =
2067 (std::fabs(ci->radius - r) < std::numeric_limits<double>::epsilon() * vpMath::maximum(ci->radius, r));
2068 }
2069 }
2070
2071 if (!already_here) {
2072 ci = new vpMbtDistanceCircle;
2073
2074 ci->setCameraParameters(m_cam);
2075 ci->buildFrom(P1, P2, P3, r);
2076 ci->setMovingEdge(&me);
2077 ci->setIndex(ncircle);
2078 ci->setName(name);
2079 ci->index_polygon = idFace;
2080 ci->hiddenface = &faces;
2081
2082 // if(clippingFlag != vpPolygon3D::NO_CLIPPING)
2083 // ci->getPolygon().setClipping(clippingFlag);
2084
2085 // if((clippingFlag & vpPolygon3D::NEAR_CLIPPING) ==
2086 // vpPolygon3D::NEAR_CLIPPING)
2087 // ci->getPolygon().setNearClippingDistance(distNearClip);
2088
2089 // if((clippingFlag & vpPolygon3D::FAR_CLIPPING) ==
2090 // vpPolygon3D::FAR_CLIPPING)
2091 // ci->getPolygon().setFarClippingDistance(distFarClip);
2092
2093 ncircle += 1;
2094 circles[i].push_back(ci);
2095 }
2096 upScale(i);
2097 }
2098 }
2099 }
2100 }
2101
2102 /*!
2103 Add a cylinder to the list of cylinders.
2104
2105 \param P1 : The first extremity of the axis.
2106 \param P2 : The second extremity of the axis.
2107 \param r : The radius of the cylinder.
2108 \param idFace : The index of the face.
2109 \param name : the optional name of the cylinder
2110 */
addCylinder(const vpPoint & P1,const vpPoint & P2,double r,int idFace,const std::string & name)2111 void vpMbEdgeTracker::addCylinder(const vpPoint &P1, const vpPoint &P2, double r, int idFace,
2112 const std::string &name)
2113 {
2114 {
2115 bool already_here = false;
2116 vpMbtDistanceCylinder *cy;
2117
2118 for (unsigned int i = 0; i < scales.size(); i += 1) {
2119 if (scales[i]) {
2120 downScale(i);
2121 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[i].begin(); it != cylinders[i].end();
2122 ++it) {
2123 cy = *it;
2124 if ((samePoint(*(cy->p1), P1) && samePoint(*(cy->p2), P2)) ||
2125 (samePoint(*(cy->p1), P2) && samePoint(*(cy->p2), P1))) {
2126 already_here =
2127 (std::fabs(cy->radius - r) < std::numeric_limits<double>::epsilon() * vpMath::maximum(cy->radius, r));
2128 }
2129 }
2130
2131 if (!already_here) {
2132 cy = new vpMbtDistanceCylinder;
2133
2134 cy->setCameraParameters(m_cam);
2135 cy->buildFrom(P1, P2, r);
2136 cy->setMovingEdge(&me);
2137 cy->setIndex(ncylinder);
2138 cy->setName(name);
2139 cy->index_polygon = idFace;
2140 cy->hiddenface = &faces;
2141 ncylinder += 1;
2142 cylinders[i].push_back(cy);
2143 }
2144 upScale(i);
2145 }
2146 }
2147 }
2148 }
2149
2150 /*!
2151 Remove a cylinder by its name.
2152
2153 \param name : The name of the cylinder to remove.
2154 */
removeCylinder(const std::string & name)2155 void vpMbEdgeTracker::removeCylinder(const std::string &name)
2156 {
2157 vpMbtDistanceCylinder *cy;
2158
2159 for (unsigned int i = 0; i < scales.size(); i++) {
2160 if (scales[i]) {
2161 for (std::list<vpMbtDistanceCylinder *>::iterator it = cylinders[i].begin(); it != cylinders[i].end(); ++it) {
2162 cy = *it;
2163 if (name.compare(cy->getName()) == 0) {
2164 cylinders[i].erase(it);
2165 break;
2166 }
2167 }
2168 }
2169 }
2170 }
2171
2172 /*!
2173 Remove a circle by its name.
2174
2175 \param name : The name of the circle to remove.
2176 */
removeCircle(const std::string & name)2177 void vpMbEdgeTracker::removeCircle(const std::string &name)
2178 {
2179 vpMbtDistanceCircle *ci;
2180
2181 for (unsigned int i = 0; i < scales.size(); i++) {
2182 if (scales[i]) {
2183 for (std::list<vpMbtDistanceCircle *>::iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
2184 ci = *it;
2185 if (name.compare(ci->getName()) == 0) {
2186 circles[i].erase(it);
2187 break;
2188 }
2189 }
2190 }
2191 }
2192 }
2193
2194 /*!
2195 Add a polygon to the list of polygons.
2196
2197 \param p : The polygon to add.
2198 */
addPolygon(vpMbtPolygon & p)2199 void vpMbEdgeTracker::addPolygon(vpMbtPolygon &p)
2200 {
2201 unsigned int nbpt = p.getNbPoint();
2202 if (nbpt > 0) {
2203 for (unsigned int i = 0; i < nbpt - 1; i++)
2204 addLine(p.p[i], p.p[i + 1], p.getIndex());
2205 addLine(p.p[nbpt - 1], p.p[0], p.getIndex());
2206 }
2207 }
2208
2209 /*!
2210 Detect the visible faces in the image and says if a new one appeared.
2211
2212 \warning If in one iteration one face appears and one disappears, then the
2213 function will not detect the new face.
2214
2215 \param I : Image to test if a face is entirely in the image.
2216 \param cMo : The pose of the camera used to project the 3D model into the
2217 image. \param newvisibleline : This parameter is set to true if a new face
2218 appeared.
2219 */
visibleFace(const vpImage<unsigned char> & I,const vpHomogeneousMatrix & cMo,bool & newvisibleline)2220 void vpMbEdgeTracker::visibleFace(const vpImage<unsigned char> &I, const vpHomogeneousMatrix &cMo,
2221 bool &newvisibleline)
2222 {
2223 unsigned int n;
2224 bool changed = false;
2225
2226 if (!useOgre) {
2227 // n = faces.setVisible(_I.getWidth(), I.getHeight(), m_cam, cMo, vpMath::rad(89), vpMath::rad(89),
2228 // changed);
2229 n = faces.setVisible(I.getWidth(), I.getHeight(), m_cam, cMo, angleAppears, angleDisappears, changed);
2230 } else {
2231 #ifdef VISP_HAVE_OGRE
2232 n = faces.setVisibleOgre(I.getWidth(), I.getHeight(), m_cam, cMo, angleAppears, angleDisappears, changed);
2233 #else
2234 n = faces.setVisible(I.getWidth(), I.getHeight(), m_cam, cMo, angleAppears, angleDisappears, changed);
2235 #endif
2236 }
2237
2238 if (n > nbvisiblepolygone) {
2239 // cout << "une nouvelle face est visible " << endl;
2240 newvisibleline = true;
2241 } else
2242 newvisibleline = false;
2243
2244 nbvisiblepolygone = n;
2245 }
2246
2247 /*!
2248 Add the lines to track from the polygon description. If the polygon has only
2249 two points, it defines a single line that is always visible. If it has three
2250 or more corners, it defines a face. In that case the visibility of the face
2251 is computed in order to track the corresponding lines only if the face is
2252 visible.
2253
2254 The id of the polygon is supposed to be set prior calling this function.
2255
2256 This method is called from the loadModel() one to add a face of the object
2257 to track.
2258
2259 \param polygon : The polygon describing the set of lines that has to be
2260 tracked.
2261 */
initFaceFromCorners(vpMbtPolygon & polygon)2262 void vpMbEdgeTracker::initFaceFromCorners(vpMbtPolygon &polygon)
2263 {
2264 unsigned int nbpt = polygon.getNbPoint();
2265 if (nbpt > 0) {
2266 for (unsigned int i = 0; i < nbpt - 1; i++)
2267 vpMbEdgeTracker::addLine(polygon.p[i], polygon.p[i + 1], polygon.getIndex(), polygon.getName());
2268 vpMbEdgeTracker::addLine(polygon.p[nbpt - 1], polygon.p[0], polygon.getIndex(), polygon.getName());
2269 }
2270 }
2271 /*!
2272 Add the lines to track from the polygon description. If the polygon has only
2273 two points, it defines a single line that is always visible. If it has three
2274 or more corners, it defines a face. In that case the visibility of the face
2275 is computed in order to track the corresponding lines only if the face is
2276 visible.
2277
2278 The id of the polygon is supposed to be set prior calling this function.
2279
2280 This method is called from the loadModel() one to add a face of the object
2281 to track.
2282
2283 \param polygon : The polygon describing the set of lines that has to be
2284 tracked.
2285 */
initFaceFromLines(vpMbtPolygon & polygon)2286 void vpMbEdgeTracker::initFaceFromLines(vpMbtPolygon &polygon)
2287 {
2288 unsigned int nbpt = polygon.getNbPoint();
2289 if (nbpt > 0) {
2290 for (unsigned int i = 0; i < nbpt - 1; i++)
2291 vpMbEdgeTracker::addLine(polygon.p[i], polygon.p[i + 1], polygon.getIndex(), polygon.getName());
2292 }
2293 }
2294
initMbtTracking(unsigned int & nberrors_lines,unsigned int & nberrors_cylinders,unsigned int & nberrors_circles)2295 unsigned int vpMbEdgeTracker::initMbtTracking(unsigned int &nberrors_lines, unsigned int &nberrors_cylinders,
2296 unsigned int &nberrors_circles)
2297 {
2298 unsigned int nbrow = 0;
2299 nberrors_lines = 0;
2300 nberrors_cylinders = 0;
2301 nberrors_circles = 0;
2302
2303 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
2304 ++it) {
2305
2306 vpMbtDistanceLine *l = *it;
2307
2308 if (l->isTracked()) {
2309 l->initInteractionMatrixError();
2310 nbrow += l->nbFeatureTotal;
2311 nberrors_lines += l->nbFeatureTotal;
2312 }
2313 }
2314
2315 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
2316 it != cylinders[scaleLevel].end(); ++it) {
2317 vpMbtDistanceCylinder *cy = *it;
2318
2319 if (cy->isTracked()) {
2320 cy->initInteractionMatrixError();
2321 nbrow += cy->nbFeature;
2322 nberrors_cylinders += cy->nbFeature;
2323 }
2324 }
2325
2326 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
2327 it != circles[scaleLevel].end(); ++it) {
2328 vpMbtDistanceCircle *ci = *it;
2329
2330 if (ci->isTracked()) {
2331 ci->initInteractionMatrixError();
2332 nbrow += ci->nbFeature;
2333 nberrors_circles += ci->nbFeature;
2334 }
2335 }
2336
2337 return nbrow;
2338 }
2339
2340 /*!
2341 Add a circle to track from its center, 3 points (including the center)
2342 defining the plane that contain the circle and its radius.
2343
2344 \param p1 : Center of the circle.
2345 \param p2,p3 : Two points on the plane containing the circle. With the
2346 center of the circle we have 3 points defining the plane that contains the
2347 circle. \param radius : Radius of the circle. \param idFace : Index of the
2348 face associated to the circle to handle visibility test. \param name : The
2349 optional name of the circle.
2350 */
initCircle(const vpPoint & p1,const vpPoint & p2,const vpPoint & p3,double radius,int idFace,const std::string & name)2351 void vpMbEdgeTracker::initCircle(const vpPoint &p1, const vpPoint &p2, const vpPoint &p3, double radius,
2352 int idFace, const std::string &name)
2353 {
2354 addCircle(p1, p2, p3, radius, (int)idFace, name);
2355 }
2356
2357 /*!
2358 Add a cylinder to track from two points on the axis (defining the length of
2359 the cylinder) and its radius.
2360
2361 \param p1 : First point on the axis.
2362 \param p2 : Second point on the axis.
2363 \param radius : Radius of the cylinder.
2364 \param idFace : Id of the face that is associated to the cylinder to handle
2365 visibility test. \param name : The optional name of the cylinder.
2366 */
initCylinder(const vpPoint & p1,const vpPoint & p2,double radius,int idFace,const std::string & name)2367 void vpMbEdgeTracker::initCylinder(const vpPoint &p1, const vpPoint &p2, double radius, int idFace,
2368 const std::string &name)
2369 {
2370 addCylinder(p1, p2, radius, (int)idFace, name);
2371 }
2372
2373 /*!
2374 Reset the tracker. The model is removed and the pose is set to identity.
2375 The tracker needs to be initialized with a new model and a new pose.
2376
2377 */
resetTracker()2378 void vpMbEdgeTracker::resetTracker()
2379 {
2380 m_cMo.eye();
2381 vpMbtDistanceLine *l;
2382 vpMbtDistanceCylinder *cy;
2383 vpMbtDistanceCircle *ci;
2384
2385 for (unsigned int i = 0; i < scales.size(); i += 1) {
2386 if (scales[i]) {
2387 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
2388 l = *it;
2389 if (l != NULL)
2390 delete l;
2391 l = NULL;
2392 }
2393
2394 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[i].begin(); it != cylinders[i].end();
2395 ++it) {
2396 cy = *it;
2397 if (cy != NULL)
2398 delete cy;
2399 cy = NULL;
2400 }
2401
2402 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
2403 ci = *it;
2404 if (ci != NULL)
2405 delete ci;
2406 ci = NULL;
2407 }
2408 lines[i].clear();
2409 cylinders[i].clear();
2410 circles[i].clear();
2411 }
2412 }
2413
2414 faces.reset();
2415
2416 useScanLine = false;
2417
2418 #ifdef VISP_HAVE_OGRE
2419 useOgre = false;
2420 #endif
2421
2422 m_computeInteraction = true;
2423 nline = 0;
2424 ncylinder = 0;
2425 m_lambda = 1.0;
2426 nbvisiblepolygone = 0;
2427 percentageGdPt = 0.4;
2428
2429 angleAppears = vpMath::rad(89);
2430 angleDisappears = vpMath::rad(89);
2431 clippingFlag = vpPolygon3D::NO_CLIPPING;
2432
2433 m_optimizationMethod = vpMbTracker::GAUSS_NEWTON_OPT;
2434
2435 // reinitialization of the scales.
2436 this->setScales(scales);
2437 }
2438
2439 /*!
2440 Re-initialize the model used by the tracker.
2441
2442 \param I : The image containing the object to initialize.
2443 \param cad_name : Path to the file containing the 3D model description.
2444 \param cMo : The new vpHomogeneousMatrix between the camera and the new
2445 model
2446 \param verbose : verbose option to print additional information when
2447 loading CAO model files which include other CAO model files.
2448 \param T : optional transformation matrix (currently only for .cao) to transform
2449 3D points expressed in the original object frame to the desired object frame.
2450 */
reInitModel(const vpImage<unsigned char> & I,const std::string & cad_name,const vpHomogeneousMatrix & cMo,bool verbose,const vpHomogeneousMatrix & T)2451 void vpMbEdgeTracker::reInitModel(const vpImage<unsigned char> &I, const std::string &cad_name,
2452 const vpHomogeneousMatrix &cMo, bool verbose,
2453 const vpHomogeneousMatrix &T)
2454 {
2455 m_cMo.eye();
2456 vpMbtDistanceLine *l;
2457 vpMbtDistanceCylinder *cy;
2458 vpMbtDistanceCircle *ci;
2459
2460 for (unsigned int i = 0; i < scales.size(); i += 1) {
2461 if (scales[i]) {
2462 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
2463 l = *it;
2464 if (l != NULL)
2465 delete l;
2466 l = NULL;
2467 }
2468
2469 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[i].begin(); it != cylinders[i].end();
2470 ++it) {
2471 cy = *it;
2472 if (cy != NULL)
2473 delete cy;
2474 cy = NULL;
2475 }
2476
2477 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
2478 ci = *it;
2479 if (ci != NULL)
2480 delete ci;
2481 ci = NULL;
2482 }
2483
2484 lines[i].clear();
2485 cylinders[i].clear();
2486 circles[i].clear();
2487 }
2488 }
2489
2490 faces.reset();
2491
2492 // compute_interaction=1;
2493 nline = 0;
2494 ncylinder = 0;
2495 ncircle = 0;
2496 // lambda = 1;
2497 nbvisiblepolygone = 0;
2498
2499 loadModel(cad_name, verbose, T);
2500 initFromPose(I, cMo);
2501 }
2502
2503 /*!
2504 Return the number of good points (vpMeSite) tracked. A good point is a
2505 vpMeSite with its flag "state" equal to 0. Only these points are used
2506 during the virtual visual servoing stage.
2507
2508 \exception vpException::dimensionError if level does not represent a used
2509 level.
2510
2511 \return the number of good points.
2512 */
getNbPoints(unsigned int level) const2513 unsigned int vpMbEdgeTracker::getNbPoints(unsigned int level) const
2514 {
2515 if ((level > scales.size()) || !scales[level]) {
2516 throw vpException(vpException::dimensionError, "Cannot get the number of points for level %d: level is not used",
2517 level);
2518 }
2519
2520 unsigned int nbGoodPoints = 0;
2521 vpMbtDistanceLine *l;
2522 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[level].begin(); it != lines[level].end(); ++it) {
2523 l = *it;
2524 if (l->isVisible() && l->isTracked()) {
2525 for (size_t a = 0; a < l->meline.size(); a++) {
2526 if (l->nbFeature[a] != 0)
2527 for (std::list<vpMeSite>::const_iterator itme = l->meline[a]->getMeList().begin();
2528 itme != l->meline[a]->getMeList().end(); ++itme) {
2529 if (itme->getState() == vpMeSite::NO_SUPPRESSION)
2530 nbGoodPoints++;
2531 }
2532 }
2533 }
2534 }
2535
2536 vpMbtDistanceCylinder *cy;
2537 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[level].begin(); it != cylinders[level].end();
2538 ++it) {
2539 cy = *it;
2540 if (cy->isVisible() && cy->isTracked() && (cy->meline1 != NULL || cy->meline2 != NULL)) {
2541 for (std::list<vpMeSite>::const_iterator itme1 = cy->meline1->getMeList().begin();
2542 itme1 != cy->meline1->getMeList().end(); ++itme1) {
2543 if (itme1->getState() == vpMeSite::NO_SUPPRESSION)
2544 nbGoodPoints++;
2545 }
2546 for (std::list<vpMeSite>::const_iterator itme2 = cy->meline2->getMeList().begin();
2547 itme2 != cy->meline2->getMeList().end(); ++itme2) {
2548 if (itme2->getState() == vpMeSite::NO_SUPPRESSION)
2549 nbGoodPoints++;
2550 }
2551 }
2552 }
2553
2554 vpMbtDistanceCircle *ci;
2555 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[level].begin(); it != circles[level].end(); ++it) {
2556 ci = *it;
2557 if (ci->isVisible() && ci->isTracked() && ci->meEllipse != NULL) {
2558 for (std::list<vpMeSite>::const_iterator itme = ci->meEllipse->getMeList().begin();
2559 itme != ci->meEllipse->getMeList().end(); ++itme) {
2560 if (itme->getState() == vpMeSite::NO_SUPPRESSION)
2561 nbGoodPoints++;
2562 }
2563 }
2564 }
2565
2566 return nbGoodPoints;
2567 }
2568
2569 /*!
2570 Set the scales to use to realize the tracking. The vector of boolean
2571 activates or not the scales to set for the object tracking. The first
2572 element of the list correspond to the tracking on the full image, the second
2573 element corresponds to the tracking on an image subsampled by two.
2574
2575 Using multi scale tracking allows to track the object with greater moves. It
2576 requires the computation of a pyramid of images, but the total tracking can
2577 be faster than a tracking based only on the full scale. The pose is computed
2578 from the smallest image to the biggest. This may be dangerous if the object
2579 to track is small in the image, because the subsampled scale(s) will have
2580 only few points to compute the pose (it could result in a loss of
2581 precision).
2582
2583 \warning This method must be used before the tracker has been initialized (
2584 before the call of the loadConfigFile() or loadModel() methods).
2585
2586 \warning At least one level must be activated.
2587
2588 \param scale : The vector describing the levels to use.
2589 */
setScales(const std::vector<bool> & scale)2590 void vpMbEdgeTracker::setScales(const std::vector<bool> &scale)
2591 {
2592 unsigned int nbActivatedLevels = 0;
2593 for (unsigned int i = 0; i < scale.size(); i++) {
2594 if (scale[i]) {
2595 nbActivatedLevels++;
2596 }
2597 }
2598
2599 if (scale.empty() || (nbActivatedLevels == 0)) {
2600 vpERROR_TRACE(" !! WARNING : must use at least one level for the "
2601 "tracking. Use the global one");
2602 this->scales.resize(0);
2603 this->scales.push_back(true);
2604
2605 lines.resize(1);
2606 lines[0].clear();
2607
2608 cylinders.resize(1);
2609 cylinders[0].clear();
2610
2611 circles.resize(1);
2612 circles[0].clear();
2613 } else {
2614 this->scales = scale;
2615
2616 lines.resize(scale.size());
2617 cylinders.resize(scale.size());
2618 circles.resize(scale.size());
2619
2620 for (unsigned int i = 0; i < lines.size(); i++) {
2621 lines[i].clear();
2622 cylinders[i].clear();
2623 circles[i].clear();
2624 }
2625 }
2626 }
2627
2628 /*!
2629 Set the far distance for clipping.
2630
2631 \param dist : Far clipping value.
2632 */
setFarClippingDistance(const double & dist)2633 void vpMbEdgeTracker::setFarClippingDistance(const double &dist)
2634 {
2635 if ((clippingFlag & vpPolygon3D::NEAR_CLIPPING) == vpPolygon3D::NEAR_CLIPPING && dist <= distNearClip)
2636 std::cerr << "Far clipping value cannot be inferior than near clipping "
2637 "value. Far clipping won't be considered."
2638 << std::endl;
2639 else if (dist < 0)
2640 std::cerr << "Far clipping value cannot be inferior than 0. Far clipping "
2641 "won't be considered."
2642 << std::endl;
2643 else {
2644 vpMbTracker::setFarClippingDistance(dist);
2645 vpMbtDistanceLine *l;
2646
2647 for (unsigned int i = 0; i < scales.size(); i += 1) {
2648 if (scales[i]) {
2649 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
2650 l = *it;
2651 l->getPolygon().setFarClippingDistance(distFarClip);
2652 }
2653 }
2654 }
2655 }
2656 }
2657
2658 /*!
2659 Set the near distance for clipping.
2660
2661 \param dist : Near clipping value.
2662 */
setNearClippingDistance(const double & dist)2663 void vpMbEdgeTracker::setNearClippingDistance(const double &dist)
2664 {
2665 if ((clippingFlag & vpPolygon3D::FAR_CLIPPING) == vpPolygon3D::FAR_CLIPPING && dist >= distFarClip)
2666 std::cerr << "Near clipping value cannot be superior than far clipping "
2667 "value. Near clipping won't be considered."
2668 << std::endl;
2669 else if (dist < 0)
2670 std::cerr << "Near clipping value cannot be inferior than 0. Near "
2671 "clipping won't be considered."
2672 << std::endl;
2673 else {
2674 vpMbTracker::setNearClippingDistance(dist);
2675 vpMbtDistanceLine *l;
2676
2677 for (unsigned int i = 0; i < scales.size(); i += 1) {
2678 if (scales[i]) {
2679 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
2680 l = *it;
2681 l->getPolygon().setNearClippingDistance(distNearClip);
2682 }
2683 }
2684 }
2685 }
2686 }
2687
2688 /*!
2689 Specify which clipping to use.
2690
2691 \sa vpMbtPolygonClipping
2692
2693 \param flags : New clipping flags.
2694 */
setClipping(const unsigned int & flags)2695 void vpMbEdgeTracker::setClipping(const unsigned int &flags)
2696 {
2697 vpMbTracker::setClipping(flags);
2698
2699 vpMbtDistanceLine *l;
2700
2701 for (unsigned int i = 0; i < scales.size(); i += 1) {
2702 if (scales[i]) {
2703 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
2704 l = *it;
2705 l->getPolygon().setClipping(clippingFlag);
2706 }
2707 }
2708 }
2709 }
2710
2711 /*!
2712 Compute the pyramid of image associated to the image in parameter. The
2713 scales computed are the ones corresponding to the scales attribute of the
2714 class. If OpenCV is detected, the functions used to computed a smoothed
2715 pyramid come from OpenCV, otherwise a simple subsampling (no smoothing, no
2716 interpolation) is realized.
2717
2718 \warning The pyramid contains pointers to vpImage. To properly deallocate
2719 the pyramid. All the element but the first (which is a pointer to the input
2720 image) must be freed. A proper cleaning is implemented in the cleanPyramid()
2721 method.
2722
2723 \param _I : The input image.
2724 \param _pyramid : The pyramid of image to build from the input image.
2725 */
initPyramid(const vpImage<unsigned char> & _I,std::vector<const vpImage<unsigned char> * > & _pyramid)2726 void vpMbEdgeTracker::initPyramid(const vpImage<unsigned char> &_I,
2727 std::vector<const vpImage<unsigned char> *> &_pyramid)
2728 {
2729 _pyramid.resize(scales.size());
2730
2731 if (scales[0]) {
2732 _pyramid[0] = &_I;
2733 } else {
2734 _pyramid[0] = NULL;
2735 }
2736
2737 for (unsigned int i = 1; i < _pyramid.size(); i += 1) {
2738 if (scales[i]) {
2739 unsigned int cScale = static_cast<unsigned int>(pow(2., (int)i));
2740 vpImage<unsigned char> *I = new vpImage<unsigned char>(_I.getHeight() / cScale, _I.getWidth() / cScale);
2741 #if (defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION < 0x020408))
2742 IplImage *vpI0 = cvCreateImageHeader(cvSize((int)_I.getWidth(), (int)_I.getHeight()), IPL_DEPTH_8U, 1);
2743 vpI0->imageData = (char *)(_I.bitmap);
2744 IplImage *vpI =
2745 cvCreateImage(cvSize((int)(_I.getWidth() / cScale), (int)(_I.getHeight() / cScale)), IPL_DEPTH_8U, 1);
2746 cvResize(vpI0, vpI, CV_INTER_NN);
2747 vpImageConvert::convert(vpI, *I);
2748 cvReleaseImage(&vpI);
2749 vpI0->imageData = NULL;
2750 cvReleaseImageHeader(&vpI0);
2751 #else
2752 for (unsigned int k = 0, ii = 0; k < I->getHeight(); k += 1, ii += cScale) {
2753 for (unsigned int l = 0, jj = 0; l < I->getWidth(); l += 1, jj += cScale) {
2754 (*I)[k][l] = _I[ii][jj];
2755 }
2756 }
2757 #endif
2758 _pyramid[i] = I;
2759 } else {
2760 _pyramid[i] = NULL;
2761 }
2762 }
2763 }
2764
2765 /*!
2766 Clean the pyramid of image allocated with the initPyramid() method. The
2767 vector has a size equal to zero at the end of the method.
2768
2769 \param _pyramid : The pyramid of image to clean.
2770 */
cleanPyramid(std::vector<const vpImage<unsigned char> * > & _pyramid)2771 void vpMbEdgeTracker::cleanPyramid(std::vector<const vpImage<unsigned char> *> &_pyramid)
2772 {
2773 if (_pyramid.size() > 0) {
2774 _pyramid[0] = NULL;
2775 for (unsigned int i = 1; i < _pyramid.size(); i += 1) {
2776 if (_pyramid[i] != NULL) {
2777 delete _pyramid[i];
2778 _pyramid[i] = NULL;
2779 }
2780 }
2781 _pyramid.resize(0);
2782 }
2783 }
2784
2785 /*!
2786 Get the list of the lines tracked for the specified level. Each line
2787 contains the list of the vpMeSite.
2788
2789 \throw vpException::dimensionError if the second parameter does not
2790 correspond to an used level.
2791
2792 \param level : Level corresponding to the list to return.
2793 \param linesList : The list of the lines of the model.
2794 */
getLline(std::list<vpMbtDistanceLine * > & linesList,unsigned int level) const2795 void vpMbEdgeTracker::getLline(std::list<vpMbtDistanceLine *> &linesList, unsigned int level) const
2796 {
2797 if (level > scales.size() || !scales[level]) {
2798 std::ostringstream oss;
2799 oss << level;
2800 std::string errorMsg = "level " + oss.str() + " is not used, cannot get its distance lines.";
2801 throw vpException(vpException::dimensionError, errorMsg);
2802 }
2803
2804 linesList = lines[level];
2805 }
2806
2807 /*!
2808 Get the list of the cylinders tracked for the specified level. Each cylinder
2809 contains the list of the vpMeSite.
2810
2811 \throw vpException::dimensionError if the second parameter does not
2812 correspond to an used level.
2813
2814 \param level : Level corresponding to the list to return.
2815 \param cylindersList : The list of the cylinders of the model.
2816 */
getLcylinder(std::list<vpMbtDistanceCylinder * > & cylindersList,unsigned int level) const2817 void vpMbEdgeTracker::getLcylinder(std::list<vpMbtDistanceCylinder *> &cylindersList, unsigned int level) const
2818 {
2819 if (level > scales.size() || !scales[level]) {
2820 std::ostringstream oss;
2821 oss << level;
2822 std::string errorMsg = "level " + oss.str() + " is not used, cannot get its distance lines.";
2823 throw vpException(vpException::dimensionError, errorMsg);
2824 }
2825
2826 cylindersList = cylinders[level];
2827 }
2828
2829 /*!
2830 Get the list of the circles tracked for the specified level. Each circle
2831 contains the list of the vpMeSite.
2832
2833 \throw vpException::dimensionError if the second parameter does not
2834 correspond to an used level.
2835
2836 \param level : Level corresponding to the list to return.
2837 \param circlesList : The list of the circles of the model.
2838 */
getLcircle(std::list<vpMbtDistanceCircle * > & circlesList,unsigned int level) const2839 void vpMbEdgeTracker::getLcircle(std::list<vpMbtDistanceCircle *> &circlesList, unsigned int level) const
2840 {
2841 if (level > scales.size() || !scales[level]) {
2842 std::ostringstream oss;
2843 oss << level;
2844 std::string errorMsg = "level " + oss.str() + " is not used, cannot get its distance lines.";
2845 throw vpException(vpException::dimensionError, errorMsg);
2846 }
2847
2848 circlesList = circles[level];
2849 }
2850
2851 /*!
2852 Modify the camera parameters to have them corresponding to the current
2853 scale. The new parameters are divided by \f$ 2^{\_scale} \f$.
2854
2855 \param _scale : Scale to use.
2856 */
downScale(const unsigned int _scale)2857 void vpMbEdgeTracker::downScale(const unsigned int _scale)
2858 {
2859 const double ratio = pow(2., (int)_scale);
2860 scaleLevel = _scale;
2861
2862 vpMatrix K = m_cam.get_K();
2863
2864 K[0][0] /= ratio;
2865 K[1][1] /= ratio;
2866 K[0][2] /= ratio;
2867 K[1][2] /= ratio;
2868
2869 m_cam.initFromCalibrationMatrix(K);
2870 }
2871
2872 /*!
2873 Modify the camera parameters to have them corresponding to the current
2874 scale. The new parameters are multiplied by \f$ 2^{\_scale} \f$.
2875
2876 \param _scale : Scale to use.
2877 */
upScale(const unsigned int _scale)2878 void vpMbEdgeTracker::upScale(const unsigned int _scale)
2879 {
2880 const double ratio = pow(2., (int)_scale);
2881 scaleLevel = 0;
2882
2883 vpMatrix K = m_cam.get_K();
2884
2885 K[0][0] *= ratio;
2886 K[1][1] *= ratio;
2887 K[0][2] *= ratio;
2888 K[1][2] *= ratio;
2889
2890 m_cam.initFromCalibrationMatrix(K);
2891 }
2892
2893 /*!
2894 Re initialize the moving edges associated to a given level. This method is
2895 used to re-initialize the level if the tracking failed on this level but
2896 succeeded on the other one.
2897
2898 \param _lvl : The level to re-initialize.
2899 */
reInitLevel(const unsigned int _lvl)2900 void vpMbEdgeTracker::reInitLevel(const unsigned int _lvl)
2901 {
2902 unsigned int scaleLevel_1 = scaleLevel;
2903 scaleLevel = _lvl;
2904
2905 vpMbtDistanceLine *l;
2906 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[scaleLevel].begin(); it != lines[scaleLevel].end();
2907 ++it) {
2908 if ((*it)->isTracked()) {
2909 l = *it;
2910 l->reinitMovingEdge(*Ipyramid[_lvl], m_cMo, m_mask);
2911 }
2912 }
2913
2914 vpMbtDistanceCylinder *cy;
2915 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[scaleLevel].begin();
2916 it != cylinders[scaleLevel].end(); ++it) {
2917 if ((*it)->isTracked()) {
2918 cy = *it;
2919 cy->reinitMovingEdge(*Ipyramid[_lvl], m_cMo, m_mask);
2920 }
2921 }
2922
2923 vpMbtDistanceCircle *ci;
2924 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[scaleLevel].begin();
2925 it != circles[scaleLevel].end(); ++it) {
2926 if ((*it)->isTracked()) {
2927 ci = *it;
2928 ci->reinitMovingEdge(*Ipyramid[_lvl], m_cMo, m_mask);
2929 }
2930 }
2931
2932 trackMovingEdge(*Ipyramid[_lvl]);
2933 updateMovingEdge(*Ipyramid[_lvl]);
2934 scaleLevel = scaleLevel_1;
2935 }
2936
2937 /*!
2938 Set if the polygons that have the given name have to be considered during
2939 the tracking phase.
2940
2941 \param name : name of the polygon(s).
2942 \param useEdgeTracking : True if it has to be considered, False otherwise.
2943 */
setUseEdgeTracking(const std::string & name,const bool & useEdgeTracking)2944 void vpMbEdgeTracker::setUseEdgeTracking(const std::string &name, const bool &useEdgeTracking)
2945 {
2946 for (unsigned int i = 0; i < scales.size(); i += 1) {
2947 if (scales[i]) {
2948 for (std::list<vpMbtDistanceLine *>::const_iterator it = lines[i].begin(); it != lines[i].end(); ++it) {
2949 /*(*it)->setTracked(useEdgeTracking);
2950 for(std::list<int>::const_iterator
2951 itpoly=(*it)->Lindex_polygon.begin();
2952 itpoly!=(*it)->Lindex_polygon.end(); ++itpoly){
2953 if(faces[(*itpoly)]->getName() != name){
2954 (*it)->setTracked(true);
2955 break;
2956 }
2957 }*/
2958
2959 (*it)->setTracked(name, useEdgeTracking);
2960 }
2961
2962 for (std::list<vpMbtDistanceCylinder *>::const_iterator it = cylinders[i].begin(); it != cylinders[i].end();
2963 ++it) {
2964 if (faces[(unsigned)(*it)->index_polygon]->getName() == name) {
2965 (*it)->setTracked(useEdgeTracking);
2966 }
2967 }
2968
2969 for (std::list<vpMbtDistanceCircle *>::const_iterator it = circles[i].begin(); it != circles[i].end(); ++it) {
2970 if (faces[(unsigned)(*it)->index_polygon]->getName() == name) {
2971 (*it)->setTracked(useEdgeTracking);
2972 }
2973 }
2974 }
2975 }
2976 }
2977