Visual Servoing Platform  version 3.1.0
vpMeEllipse.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Moving edges.
33  *
34  * Authors:
35  * Eric Marchand
36  *
37  *****************************************************************************/
38 
39 #include <visp3/me/vpMeEllipse.h>
40 
41 #include <visp3/core/vpDebug.h>
42 #include <visp3/core/vpException.h>
43 #include <visp3/core/vpImagePoint.h>
44 #include <visp3/core/vpRobust.h>
45 #include <visp3/me/vpMe.h>
46 
47 #include <cmath> // std::fabs
48 #include <limits> // numeric_limits
49 #include <vector>
50 
51 void computeTheta(double &theta, vpColVector &K, const vpImagePoint &iP);
52 
61 void computeTheta(double &theta, vpColVector &K, const vpImagePoint &iP)
62 {
63  double i = iP.get_i();
64  double j = iP.get_j();
65 
66  double A = 2 * i + 2 * K[1] * j + 2 * K[2];
67  double B = 2 * K[0] * j + 2 * K[1] * i + 2 * K[3];
68 
69  theta = atan2(A, B); // Angle between the tangente and the i axis.
70 
71  while (theta > M_PI) {
72  theta -= M_PI;
73  }
74  while (theta < 0) {
75  theta += M_PI;
76  }
77 }
78 
83  : K(), iPc(), a(0.), b(0.), e(0.), iP1(), iP2(), alpha1(0), alpha2(2 * M_PI), ce(0.), se(0.), angle(), m00(0.),
84  mu11(0.), mu20(0.), mu02(0.), m10(0.), m01(0.), m11(0.), m02(0.), m20(0.), thresholdWeight(0.2), expecteddensity(0.)
85 {
86  // redimensionnement du vecteur de parametre
87  // i^2 + K0 j^2 + 2 K1 i j + 2 K2 i + 2 K3 j + K4
88 
89  K.resize(5);
90 
91  // j1 = j2 = i1 = i2 = 0;
92  iP1.set_i(0);
93  iP1.set_j(0);
94  iP2.set_i(0);
95  iP2.set_j(0);
96 }
97 
102  : vpMeTracker(meellipse), K(meellipse.K), iPc(meellipse.iPc), a(0.), b(0.), e(0.), iP1(meellipse.iP1),
103  iP2(meellipse.iP2), alpha1(0), alpha2(2 * M_PI), ce(0.), se(0.), angle(meellipse.angle), m00(0.), mu11(0.),
104  mu20(0.), mu02(0.), m10(0.), m01(0.), m11(0.), m02(0.), m20(0.), thresholdWeight(0.2), expecteddensity(0.)
105 {
106  a = meellipse.a;
107  b = meellipse.b;
108  e = meellipse.e;
109 
110  alpha1 = meellipse.alpha1;
111  alpha2 = meellipse.alpha2;
112  ce = meellipse.ce;
113  se = meellipse.se;
114 
115  m00 = meellipse.m00;
116  mu11 = meellipse.mu11;
117  mu20 = meellipse.mu20;
118  mu02 = meellipse.mu02;
119  m10 = meellipse.m10;
120  m01 = meellipse.m01;
121  m11 = meellipse.m11;
122  m02 = meellipse.m02;
123  m20 = meellipse.m20;
124  thresholdWeight = meellipse.thresholdWeight;
125 
126  expecteddensity = meellipse.expecteddensity;
127 }
128 
133 {
134  list.clear();
135  angle.clear();
136 }
137 
149 void vpMeEllipse::sample(const vpImage<unsigned char> &I)
150 {
151  if (!me) {
152  throw(vpException(vpException::fatalError, "Moving edges on ellipse tracking not initialized"));
153  }
154 
155  int height = (int)I.getHeight();
156  int width = (int)I.getWidth();
157 
158  // if (me->getSampleStep()==0)
159  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon()) {
160  std::cout << "In vpMeEllipse::sample: ";
161  std::cout << "function called with sample step = 0";
162  // return fatalError;
163  }
164 
165  vpImagePoint iP11;
166 
167  double incr = vpMath::rad(me->getSampleStep()); // angle increment en degree
168  vpColor col = vpColor::red;
169  getParameters();
170 
171  // Delete old list
172  list.clear();
173 
174  angle.clear();
175 
176  // sample positions
177  double k = alpha1;
178  while (k < alpha2) {
179  double j = a * sin(k); // equation of an ellipse
180  double i = b * cos(k); // equation of an ellipse
181 
182  // (i,j) are the coordinates on the origin centered ellipse;
183  // a rotation by "e" and a translation by (xci,jc) are done
184  // to get the coordinates of the point on the shifted ellipse
185  iP11.set_j(iPc.get_j() + ce * j + se * i);
186  iP11.set_i(iPc.get_i() - se * j + ce * i);
187 
188  vpDisplay::displayCross(I, iP11, 5, col);
189 
190  double theta;
191  computeTheta(theta, K, iP11);
192 
193  // If point is in the image, add to the sample list
194  if (!outOfImage(vpMath::round(iP11.get_i()), vpMath::round(iP11.get_j()), 0, height, width)) {
195  vpMeSite pix;
196  pix.init((int)iP11.get_i(), (int)iP11.get_j(), theta);
199 
200  if (vpDEBUG_ENABLE(3)) {
202  }
203  list.push_back(pix);
204  angle.push_back(k);
205  }
206  k += incr;
207  }
209 }
210 
226 void vpMeEllipse::reSample(const vpImage<unsigned char> &I)
227 {
228  if (!me) {
229  throw(vpException(vpException::fatalError, "Moving edges on ellipse tracking not initialized"));
230  }
231 
232  unsigned int n = numberOfSignal();
234  if ((double)n < 0.5 * expecteddensity) {
235  sample(I);
237  }
238 }
239 
249 void vpMeEllipse::getParameters()
250 {
251  double k[6];
252  for (unsigned int i = 0; i < 5; i++)
253  k[i + 1] = K[i];
254  k[0] = 1;
255 
256  double d = k[2] * k[2] - k[0] * k[1];
257 
258  iPc.set_i((k[1] * k[3] - k[2] * k[4]) / d);
259  iPc.set_j((k[0] * k[4] - k[2] * k[3]) / d);
260 
261  double sq = sqrt(vpMath::sqr(k[1] - k[0]) + 4.0 * vpMath::sqr(k[2]));
262 
263  if (std::fabs(k[2]) <= std::numeric_limits<double>::epsilon()) {
264  e = 0;
265  } else {
266  e = (k[1] - k[0] + sq) / (2.0 * k[2]);
267  e = (-1 / e);
268  }
269 
270  e = atan(e);
271 
272  if (e < 0.0)
273  e += M_PI;
274 
275  ce = cos(e);
276  se = sin(e);
277 
278  double num = 2.0 * (k[0] * iPc.get_i() * iPc.get_i() + 2.0 * k[2] * iPc.get_j() * iPc.get_i() +
279  k[1] * iPc.get_j() * iPc.get_j() - k[5]);
280  double a2 = num / (k[0] + k[1] + sq);
281  double b2 = num / (k[0] + k[1] - sq);
282 
283  a = sqrt(a2);
284  b = sqrt(b2);
285 }
286 
292 {
293  std::cout << "K" << std::endl;
294  std::cout << K.t();
295  std::cout << iPc << std::endl;
296 }
297 
307 void vpMeEllipse::computeAngle(const vpImagePoint &pt1, const vpImagePoint &pt2)
308 {
309  getParameters();
310 
311  int number_of_points = 2000;
312  double incr = 2 * M_PI / number_of_points; // angle increment
313 
314  double dmin1 = 1e6;
315  double dmin2 = 1e6;
316 
317  double k = 0;
318  while (k < 2 * M_PI) {
319 
320  double j1 = a * sin(k); // equation of an ellipse
321  double i1 = b * cos(k); // equation of an ellipse
322 
323  // (i1,j1) are the coordinates on the origin centered ellipse;
324  // a rotation by "e" and a translation by (xci,jc) are done
325  // to get the coordinates of the point on the shifted ellipse
326 
327  double j11 = iPc.get_j() + ce * j1 + se * i1;
328  double i11 = iPc.get_i() - se * j1 + ce * i1;
329 
330  double d = vpMath::sqr(pt1.get_i() - i11) + vpMath::sqr(pt1.get_j() - j11);
331  if (d < dmin1) {
332  dmin1 = d;
333  alpha1 = k;
334  }
335  d = vpMath::sqr(pt2.get_i() - i11) + vpMath::sqr(pt2.get_j() - j11);
336  if (d < dmin2) {
337  dmin2 = d;
338  alpha2 = k;
339  }
340  k += incr;
341  }
342 
343  if (alpha2 < alpha1)
344  alpha2 += 2 * M_PI;
345  // else if (alpha2 == alpha1)
346  else if (std::fabs(alpha2 - alpha1) < std::fabs(alpha1) * std::numeric_limits<double>::epsilon())
347  alpha2 += 2 * M_PI;
348 }
349 
355 void vpMeEllipse::updateTheta()
356 {
357  vpMeSite p_me;
358  double theta;
359  for (std::list<vpMeSite>::iterator it = list.begin(); it != list.end(); ++it) {
360  p_me = *it;
361  vpImagePoint iP;
362  iP.set_i(p_me.ifloat);
363  iP.set_j(p_me.jfloat);
364  computeTheta(theta, K, iP);
365  p_me.alpha = theta;
366  *it = p_me;
367  }
368 }
369 
374 void vpMeEllipse::suppressPoints()
375 {
376  // Loop through list of sites to track
377  std::list<vpMeSite>::iterator itList = list.begin();
378  for (std::list<double>::iterator it = angle.begin(); it != angle.end();) {
379  vpMeSite s = *itList; // current reference pixel
380  if (s.getState() != vpMeSite::NO_SUPPRESSION) {
381  itList = list.erase(itList);
382  it = angle.erase(it);
383  } else {
384  ++itList;
385  ++it;
386  }
387  }
388 }
389 
401 void vpMeEllipse::seekExtremities(const vpImage<unsigned char> &I)
402 {
403  if (!me) {
404  throw(vpException(vpException::fatalError, "Moving edges on ellipse tracking not initialized"));
405  }
406 
407  int rows = (int)I.getHeight();
408  int cols = (int)I.getWidth();
409 
410  vpImagePoint ip;
411 
412  unsigned int memory_range = me->getRange();
413  me->setRange(2);
414 
415  double memory_mu1 = me->getMu1();
416  me->setMu1(0.5);
417 
418  double memory_mu2 = me->getMu2();
419  me->setMu2(0.5);
420 
421  double incr = vpMath::rad(2.0);
422 
423  if (alpha2 - alpha1 < 2 * M_PI - vpMath::rad(6.0)) {
424  vpMeSite P;
425  double k = alpha1;
426  double i1, j1;
427 
428  for (unsigned int i = 0; i < 3; i++) {
429  k -= incr;
430  // while ( k < -M_PI ) { k+=2*M_PI; }
431 
432  i1 = b * cos(k); // equation of an ellipse
433  j1 = a * sin(k); // equation of an ellipse
434  P.ifloat = iPc.get_i() - se * j1 + ce * i1;
435  P.i = (int)P.ifloat;
436  P.jfloat = iPc.get_j() + ce * j1 + se * i1;
437  P.j = (int)P.jfloat;
438 
439  if (!outOfImage(P.i, P.j, 5, rows, cols)) {
440  P.track(I, me, false);
441 
442  if (P.getState() == vpMeSite::NO_SUPPRESSION) {
443  list.push_back(P);
444  angle.push_back(k);
445  if (vpDEBUG_ENABLE(3)) {
446  ip.set_i(P.i);
447  ip.set_j(P.j);
448 
450  }
451  } else {
452  if (vpDEBUG_ENABLE(3)) {
453  ip.set_i(P.i);
454  ip.set_j(P.j);
456  }
457  }
458  }
459  }
460 
461  k = alpha2;
462 
463  for (unsigned int i = 0; i < 3; i++) {
464  k += incr;
465  // while ( k > M_PI ) { k-=2*M_PI; }
466 
467  i1 = b * cos(k); // equation of an ellipse
468  j1 = a * sin(k); // equation of an ellipse
469  P.ifloat = iPc.get_i() - se * j1 + ce * i1;
470  P.i = (int)P.ifloat;
471  P.jfloat = iPc.get_j() + ce * j1 + se * i1;
472  P.j = (int)P.jfloat;
473 
474  if (!outOfImage(P.i, P.j, 5, rows, cols)) {
475  P.track(I, me, false);
476 
477  if (P.getState() == vpMeSite::NO_SUPPRESSION) {
478  list.push_back(P);
479  angle.push_back(k);
480  if (vpDEBUG_ENABLE(3)) {
481  ip.set_i(P.i);
482  ip.set_j(P.j);
483 
485  }
486  } else {
487  if (vpDEBUG_ENABLE(3)) {
488  ip.set_i(P.i);
489  ip.set_j(P.j);
491  }
492  }
493  }
494  }
495  }
496 
497  suppressPoints();
498 
499  me->setRange(memory_range);
500  me->setMu1(memory_mu1);
501  me->setMu2(memory_mu2);
502 }
503 
508 void vpMeEllipse::setExtremities()
509 {
510  double alphamin = +1e6;
511  double alphamax = -1e6;
512  double imin = 0;
513  double jmin = 0;
514  double imax = 0;
515  double jmax = 0;
516 
517  // Loop through list of sites to track
518  std::list<double>::const_iterator itAngle = angle.begin();
519 
520  for (std::list<vpMeSite>::const_iterator itList = list.begin(); itList != list.end(); ++itList) {
521  vpMeSite s = *itList; // current reference pixel
522  double alpha = *itAngle;
523  if (alpha < alphamin) {
524  alphamin = alpha;
525  imin = s.ifloat;
526  jmin = s.jfloat;
527  }
528 
529  if (alpha > alphamax) {
530  alphamax = alpha;
531  imax = s.ifloat;
532  jmax = s.jfloat;
533  }
534  ++itAngle;
535  }
536 
537  alpha1 = alphamin;
538  alpha2 = alphamax;
539  iP1.set_ij(imin, jmin);
540  iP2.set_ij(imax, jmax);
541 }
542 
548 void vpMeEllipse::leastSquare()
549 {
550  // Construction du systeme Ax=b
551  // i^2 + K0 j^2 + 2 K1 i j + 2 K2 i + 2 K3 j + K4
552  // A = (j^2 2ij 2i 2j 1) x = (K0 K1 K2 K3 K4)^T b = (-i^2 )
553  unsigned int i;
554 
555  vpMeSite p_me;
556 
557  unsigned int iter = 0;
560  r.setThreshold(2);
561  r.setIteration(0);
563  D.eye();
564  vpMatrix DA, DAmemory;
565  vpColVector DAx;
567  w = 1;
568  unsigned int nos_1 = numberOfSignal();
569 
570  if (list.size() < 3) {
571  throw(vpException(vpException::dimensionError, "Not enought moving edges to track the ellipse"));
572  }
573 
574  vpMatrix A(numberOfSignal(), 5);
575  vpColVector x(5);
576 
577  unsigned int k = 0;
578  for (std::list<vpMeSite>::const_iterator it = list.begin(); it != list.end(); ++it) {
579  p_me = *it;
580  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
581  A[k][0] = vpMath::sqr(p_me.jfloat);
582  A[k][1] = 2 * p_me.ifloat * p_me.jfloat;
583  A[k][2] = 2 * p_me.ifloat;
584  A[k][3] = 2 * p_me.jfloat;
585  A[k][4] = 1;
586 
587  b_[k] = -vpMath::sqr(p_me.ifloat);
588  k++;
589  }
590  }
591 
592  while (iter < 4) {
593  DA = D * A;
594  vpMatrix DAp;
595 
596  x = DA.pseudoInverse(1e-26) * D * b_;
597 
598  vpColVector residu(nos_1);
599  residu = b_ - A * x;
600  r.setIteration(iter);
601  r.MEstimator(vpRobust::TUKEY, residu, w);
602 
603  k = 0;
604  for (i = 0; i < nos_1; i++) {
605  D[k][k] = w[k];
606  k++;
607  }
608  iter++;
609  }
610 
611  k = 0;
612  for (std::list<vpMeSite>::iterator it = list.begin(); it != list.end(); ++it) {
613  p_me = *it;
614  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
615  if (w[k] < thresholdWeight) {
617 
618  *it = p_me;
619  }
620  k++;
621  }
622  }
623  for (i = 0; i < 5; i++)
624  K[i] = x[i];
625 
626  getParameters();
627 }
628 
639 {
640  vpMeEllipse::display(I, iPc, a, b, e, alpha1, alpha2, col);
641 }
642 
652 {
653  const unsigned int n = 5;
654  vpImagePoint iP[n];
655 
656  for (unsigned int k = 0; k < n; k++) {
657  std::cout << "Click points " << k + 1 << "/" << n;
658  std::cout << " on the ellipse in the trigonometric order" << std::endl;
659  vpDisplay::getClick(I, iP[k], true);
661  vpDisplay::flush(I);
662  std::cout << iP[k] << std::endl;
663  }
664 
665  iP1 = iP[0];
666  iP2 = iP[n - 1];
667 
668  initTracking(I, n, iP);
669 }
670 
683 void vpMeEllipse::initTracking(const vpImage<unsigned char> &I, const unsigned int n, vpImagePoint *iP)
684 {
685  vpMatrix A(n, 5);
686  vpColVector b_(n);
687  vpColVector x(5);
688 
689  // Construction du systeme Ax=b
690  // i^2 + K0 j^2 + 2 K1 i j + 2 K2 i + 2 K3 j + K4
691  // A = (j^2 2ij 2i 2j 1) x = (K0 K1 K2 K3 K4)^T b = (-i^2 )
692 
693  for (unsigned int k = 0; k < n; k++) {
694  A[k][0] = vpMath::sqr(iP[k].get_j());
695  A[k][1] = 2 * iP[k].get_i() * iP[k].get_j();
696  A[k][2] = 2 * iP[k].get_i();
697  A[k][3] = 2 * iP[k].get_j();
698  A[k][4] = 1;
699 
700  b_[k] = -vpMath::sqr(iP[k].get_i());
701  }
702 
703  K = A.pseudoInverse(1e-26) * b_;
704 
705  iP1 = iP[0];
706  iP2 = iP[n - 1];
707 
708  getParameters();
709 
710  computeAngle(iP1, iP2);
711 
713 
715  sample(I);
716 
718 
719  track(I);
720 
722  vpDisplay::flush(I);
723 }
724 
737 void vpMeEllipse::initTracking(const vpImage<unsigned char> &I, const std::vector<vpImagePoint> &iP)
738 {
739  unsigned int n = (unsigned int)(iP.size());
740  vpMatrix A(n, 5);
741  vpColVector b_(n);
742  vpColVector x(5);
743 
744  // Construction du systeme Ax=b
745  // i^2 + K0 j^2 + 2 K1 i j + 2 K2 i + 2 K3 j + K4
746  // A = (j^2 2ij 2i 2j 1) x = (K0 K1 K2 K3 K4)^T b = (-i^2 )
747 
748  for (unsigned int k = 0; k < n; k++) {
749  A[k][0] = vpMath::sqr(iP[k].get_j());
750  A[k][1] = 2 * iP[k].get_i() * iP[k].get_j();
751  A[k][2] = 2 * iP[k].get_i();
752  A[k][3] = 2 * iP[k].get_j();
753  A[k][4] = 1;
754 
755  b_[k] = -vpMath::sqr(iP[k].get_i());
756  }
757 
758  K = A.pseudoInverse(1e-26) * b_;
759 
760  iP1 = iP[0];
761  iP2 = iP[n - 1];
762 
763  getParameters();
764 
765  computeAngle(iP1, iP2);
766 
768 
770  sample(I);
771 
773 
774  track(I);
775 
777  vpDisplay::flush(I);
778 }
779 
780 void vpMeEllipse::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ic, double a_p, double b_p,
781  double e_p, double low_alpha, double high_alpha)
782 {
783  iPc = ic;
784  a = a_p;
785  b = b_p;
786  e = e_p;
787  alpha1 = low_alpha;
788  alpha2 = high_alpha;
789 
790  if (alpha2 < alpha1)
791  alpha2 += 2 * M_PI;
792 
793  ce = cos(e);
794  se = sin(e);
795 
797  sample(I);
798 
800 
801  track(I);
802 
804  vpDisplay::flush(I);
805 }
806 
813 {
815 
816  // Estimation des parametres de la droite aux moindres carre
817  suppressPoints();
818  setExtremities();
819 
820  leastSquare();
821  seekExtremities(I);
822  setExtremities();
823  leastSquare();
824 
825  // suppression des points rejetes par la regression robuste
826  suppressPoints();
827  setExtremities();
828 
829  // reechantillonage si necessaire
830  reSample(I);
831 
832  // remet a jour l'angle delta pour chaque point de la liste
833 
834  updateTheta();
835 
836  computeMoments();
837 
838  // Remise a jour de delta dans la liste de site me
839  if (vpDEBUG_ENABLE(2)) {
840  display(I, vpColor::red);
842  vpDisplay::flush(I);
843  }
844 }
845 
853 void vpMeEllipse::computeMoments()
854 {
855  double tane = tan(-1 / e);
856  m00 = M_PI * a * b;
857  m10 = m00 * iPc.get_i();
858  m01 = m00 * iPc.get_j();
859  m20 = m00 * (a * a + b * b * tane * tane) / (4 * (1 + tane * tane)) + m00 * iPc.get_i() * iPc.get_i();
860  m02 = m00 * (a * a * tane * tane + b * b) / (4 * (1 + tane * tane)) + m00 * iPc.get_j() * iPc.get_j();
861  m11 = m00 * tane * (a * a - b * b) / (4 * (1 + tane * tane)) + m00 * iPc.get_i() * iPc.get_j();
862  mu11 = m11 - iPc.get_j() * m10;
863  mu02 = m02 - iPc.get_j() * m01;
864  mu20 = m20 - iPc.get_i() * m10;
865 }
866 
867 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
868 
872 void vpMeEllipse::computeAngle(int ip1, int jp1, double &_alpha1, int ip2, int jp2, double &_alpha2)
873 {
874  getParameters();
875 
876  int number_of_points = 2000;
877  double incr = 2 * M_PI / number_of_points; // angle increment
878 
879  double dmin1 = 1e6;
880  double dmin2 = 1e6;
881 
882  double k = -M_PI;
883  while (k < M_PI) {
884 
885  double j1 = a * cos(k); // equation of an ellipse
886  double i1 = b * sin(k); // equation of an ellipse
887 
888  // (i1,j1) are the coordinates on the origin centered ellipse;
889  // a rotation by "e" and a translation by (xci,jc) are done
890  // to get the coordinates of the point on the shifted ellipse
891  double j11 = iPc.get_j() + ce * j1 - se * i1;
892  double i11 = iPc.get_i() - (se * j1 + ce * i1);
893 
894  double d = vpMath::sqr(ip1 - i11) + vpMath::sqr(jp1 - j11);
895  if (d < dmin1) {
896  dmin1 = d;
897  alpha1 = k;
898  _alpha1 = k;
899  }
900  d = vpMath::sqr(ip2 - i11) + vpMath::sqr(jp2 - j11);
901  if (d < dmin2) {
902  dmin2 = d;
903  alpha2 = k;
904  _alpha2 = k;
905  }
906  k += incr;
907  }
908 
909  if (alpha2 < alpha1)
910  alpha2 += 2 * M_PI;
911 
912  vpCDEBUG(1) << "end vpMeEllipse::computeAngle(..)" << alpha1 << " " << alpha2 << std::endl;
913 }
914 
918 void vpMeEllipse::computeAngle(int ip1, int jp1, int ip2, int jp2)
919 {
920 
921  double a1, a2;
922  computeAngle(ip1, jp1, a1, ip2, jp2, a2);
923 }
924 
925 void vpMeEllipse::initTracking(const vpImage<unsigned char> &I, const unsigned int n, unsigned *i, unsigned *j)
926 {
927  vpMatrix A(n, 5);
928  vpColVector b_(n);
929  vpColVector x(5);
930 
931  // Construction du systeme Ax=b
933  // A = (j^2 2ij 2i 2j 1) x = (K0 K1 K2 K3 K4)^T b = (-i^2 )
934 
935  for (unsigned int k = 0; k < n; k++) {
936  A[k][0] = vpMath::sqr(j[k]);
937  A[k][1] = 2 * i[k] * j[k];
938  A[k][2] = 2 * i[k];
939  A[k][3] = 2 * j[k];
940  A[k][4] = 1;
941 
942  b_[k] = -vpMath::sqr(i[k]);
943  }
944 
945  K = A.pseudoInverse(1e-26) * b_;
946  // std::cout << K << std::endl;
947 
948  iP1.set_i(i[0]);
949  iP1.set_j(j[0]);
950  iP2.set_i(i[n - 1]);
951  iP2.set_j(j[n - 1]);
952 
953  getParameters();
954  computeAngle(iP1, iP2);
956 
957  sample(I);
958 
959  // 2. On appelle ce qui n'est pas specifique
960  {
962  }
963 
964  track(I);
965 
967  vpDisplay::flush(I);
968 }
969 #endif // Deprecated
970 
994 void vpMeEllipse::display(const vpImage<unsigned char> &I, const vpImagePoint &center, const double &A, const double &B,
995  const double &E, const double &smallalpha, const double &highalpha, const vpColor &color,
996  unsigned int thickness)
997 {
998  double j1, i1;
999  vpImagePoint iP11;
1000  double j2, i2;
1001  vpImagePoint iP22;
1002  j1 = j2 = i1 = i2 = 0;
1003 
1004  double incr = vpMath::rad(2); // angle increment
1005 
1006  vpDisplay::displayCross(I, center, 20, vpColor::red, thickness);
1007 
1008  double k = smallalpha;
1009  while (k + incr < highalpha) {
1010  j1 = A * cos(k); // equation of an ellipse
1011  i1 = B * sin(k); // equation of an ellipse
1012 
1013  j2 = A * cos(k + incr); // equation of an ellipse
1014  i2 = B * sin(k + incr); // equation of an ellipse
1015 
1016  // (i1,j1) are the coordinates on the origin centered ellipse;
1017  // a rotation by "e" and a translation by (xci,jc) are done
1018  // to get the coordinates of the point on the shifted ellipse
1019  iP11.set_j(center.get_j() + cos(E) * j1 - sin(E) * i1);
1020  iP11.set_i(center.get_i() - (sin(E) * j1 + cos(E) * i1));
1021  // to get the coordinates of the point on the shifted ellipse
1022  iP22.set_j(center.get_j() + cos(E) * j2 - sin(E) * i2);
1023  iP22.set_i(center.get_i() - (sin(E) * j2 + cos(E) * i2));
1024 
1025  vpDisplay::displayLine(I, iP11, iP22, color, thickness);
1026 
1027  k += incr;
1028  }
1029 
1030  j1 = A * cos(smallalpha); // equation of an ellipse
1031  i1 = B * sin(smallalpha); // equation of an ellipse
1032 
1033  j2 = A * cos(highalpha); // equation of an ellipse
1034  i2 = B * sin(highalpha); // equation of an ellipse
1035 
1036  // (i1,j1) are the coordinates on the origin centered ellipse;
1037  // a rotation by "e" and a translation by (xci,jc) are done
1038  // to get the coordinates of the point on the shifted ellipse
1039  iP11.set_j(center.get_j() + cos(E) * j1 - sin(E) * i1);
1040  iP11.set_i(center.get_i() - (sin(E) * j1 + cos(E) * i1));
1041  // to get the coordinates of the point on the shifted ellipse
1042  iP22.set_j(center.get_j() + cos(E) * j2 - sin(E) * i2);
1043  iP22.set_i(center.get_i() - (sin(E) * j2 + cos(E) * i2));
1044 
1045  vpDisplay::displayLine(I, center, iP11, vpColor::red, thickness);
1046  vpDisplay::displayLine(I, center, iP22, vpColor::blue, thickness);
1047 }
1048 
1072 void vpMeEllipse::display(const vpImage<vpRGBa> &I, const vpImagePoint &center, const double &A, const double &B,
1073  const double &E, const double &smallalpha, const double &highalpha, const vpColor &color,
1074  unsigned int thickness)
1075 {
1076  double j1, i1;
1077  vpImagePoint iP11;
1078  double j2, i2;
1079  vpImagePoint iP22;
1080  j1 = j2 = i1 = i2 = 0;
1081 
1082  double incr = vpMath::rad(2); // angle increment
1083 
1084  vpDisplay::displayCross(I, center, 20, vpColor::red, thickness);
1085 
1086  double k = smallalpha;
1087  while (k + incr < highalpha) {
1088  j1 = A * cos(k); // equation of an ellipse
1089  i1 = B * sin(k); // equation of an ellipse
1090 
1091  j2 = A * cos(k + incr); // equation of an ellipse
1092  i2 = B * sin(k + incr); // equation of an ellipse
1093 
1094  // (i1,j1) are the coordinates on the origin centered ellipse;
1095  // a rotation by "e" and a translation by (xci,jc) are done
1096  // to get the coordinates of the point on the shifted ellipse
1097  iP11.set_j(center.get_j() + cos(E) * j1 - sin(E) * i1);
1098  iP11.set_i(center.get_i() - (sin(E) * j1 + cos(E) * i1));
1099  // to get the coordinates of the point on the shifted ellipse
1100  iP22.set_j(center.get_j() + cos(E) * j2 - sin(E) * i2);
1101  iP22.set_i(center.get_i() - (sin(E) * j2 + cos(E) * i2));
1102 
1103  vpDisplay::displayLine(I, iP11, iP22, color, thickness);
1104 
1105  k += incr;
1106  }
1107 
1108  j1 = A * cos(smallalpha); // equation of an ellipse
1109  i1 = B * sin(smallalpha); // equation of an ellipse
1110 
1111  j2 = A * cos(highalpha); // equation of an ellipse
1112  i2 = B * sin(highalpha); // equation of an ellipse
1113 
1114  // (i1,j1) are the coordinates on the origin centered ellipse;
1115  // a rotation by "e" and a translation by (xci,jc) are done
1116  // to get the coordinates of the point on the shifted ellipse
1117  iP11.set_j(center.get_j() + cos(E) * j1 - sin(E) * i1);
1118  iP11.set_i(center.get_i() - (sin(E) * j1 + cos(E) * i1));
1119  // to get the coordinates of the point on the shifted ellipse
1120  iP22.set_j(center.get_j() + cos(E) * j2 - sin(E) * i2);
1121  iP22.set_i(center.get_i() - (sin(E) * j2 + cos(E) * i2));
1122 
1123  vpDisplay::displayLine(I, center, iP11, vpColor::red, thickness);
1124  vpDisplay::displayLine(I, center, iP22, vpColor::blue, thickness);
1125 }
double a
is the semiminor axis of the ellipse.
Definition: vpMeEllipse.h:282
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:104
vpMatrix pseudoInverse(double svThreshold=1e-6) const
Definition: vpMatrix.cpp:1931
double m01
Definition: vpMeEllipse.h:313
double get_i() const
Definition: vpImagePoint.h:204
double expecteddensity
Expected number of me to track along the ellipse.
Definition: vpMeEllipse.h:319
vpMeSiteState getState() const
Definition: vpMeSite.h:188
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
void initTracking(const vpImage< unsigned char > &I)
double mu02
Definition: vpMeEllipse.h:311
void init()
Definition: vpMeSite.cpp:66
void MEstimator(const vpRobustEstimatorType method, const vpColVector &residues, vpColVector &weights)
Compute the weights according a residue vector and a PsiFunction.
Definition: vpRobust.cpp:176
double jfloat
Definition: vpMeSite.h:88
#define vpDEBUG_ENABLE(level)
Definition: vpDebug.h:538
unsigned int numberOfSignal()
Performs search in a given direction(normal) for a given distance(pixels) for a given &#39;site&#39;...
Definition: vpMeSite.h:71
double thresholdWeight
Threshold for the robust least square.
Definition: vpMeEllipse.h:317
Class to define colors available for display functionnalities.
Definition: vpColor.h:120
vpImagePoint iP1
Definition: vpMeEllipse.h:293
double alpha
Definition: vpMeSite.h:92
int i
Definition: vpMeSite.h:86
error that can be emited by ViSP classes.
Definition: vpException.h:71
Class that tracks an ellipse moving edges.
Definition: vpMeEllipse.h:106
double mu20
Definition: vpMeEllipse.h:311
static const vpColor green
Definition: vpColor.h:183
static void flush(const vpImage< unsigned char > &I)
static int round(const double x)
Definition: vpMath.h:235
double b
is the semimajor axis of the ellipse.
Definition: vpMeEllipse.h:284
double se
Value of sin(e).
Definition: vpMeEllipse.h:305
void setMu1(const double &mu_1)
Definition: vpMe.h:241
double getMu1() const
Definition: vpMe.h:155
static const vpColor red
Definition: vpColor.h:180
double ifloat
Definition: vpMeSite.h:88
virtual ~vpMeEllipse()
double m20
Definition: vpMeEllipse.h:315
void set_i(const double ii)
Definition: vpImagePoint.h:167
void track(const vpImage< unsigned char > &Im)
std::list< vpMeSite > list
Definition: vpMeTracker.h:74
vpImagePoint iP2
Definition: vpMeEllipse.h:297
double getSampleStep() const
Definition: vpMe.h:285
int outOfImage(int i, int j, int half, int row, int cols)
vpImagePoint iPc
The coordinates of the ellipse center.
Definition: vpMeEllipse.h:280
double m11
Second order raw moments.
Definition: vpMeEllipse.h:315
double alpha1
The smallest angle.
Definition: vpMeEllipse.h:299
static double sqr(double x)
Definition: vpMath.h:108
void printParameters()
double get_j() const
Definition: vpImagePoint.h:215
void setDisplay(vpMeSiteDisplayType select)
Definition: vpMeSite.h:137
void display(const vpImage< unsigned char > &I, vpColor col)
#define vpCDEBUG(level)
Definition: vpDebug.h:511
void track(const vpImage< unsigned char > &I)
Track sampled pixels.
double mu11
Second order central moments.
Definition: vpMeEllipse.h:311
double m10
First order raw moments.
Definition: vpMeEllipse.h:313
Contains abstract elements for a Distance to Feature type feature.
Definition: vpMeTracker.h:65
void setState(const vpMeSiteState &flag)
Definition: vpMeSite.h:174
double m00
Surface.
Definition: vpMeEllipse.h:309
static double rad(double deg)
Definition: vpMath.h:102
std::list< double > angle
Stores the value of the angle for each vpMeSite.
Definition: vpMeEllipse.h:307
void set_j(const double jj)
Definition: vpImagePoint.h:178
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
void setMu2(const double &mu_2)
Definition: vpMe.h:248
int j
Definition: vpMeSite.h:86
double m02
Definition: vpMeEllipse.h:315
unsigned int getHeight() const
Definition: vpImage.h:178
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
void track(const vpImage< unsigned char > &im, const vpMe *me, const bool test_contraste=true)
Definition: vpMeSite.cpp:362
vpMe * me
Moving edges initialisation parameters.
Definition: vpMeTracker.h:76
Contains an M-Estimator and various influence function.
Definition: vpRobust.h:58
double getMu2() const
Definition: vpMe.h:161
void initTracking(const vpImage< unsigned char > &I)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
double alpha2
The highest angle.
Definition: vpMeEllipse.h:301
void setRange(const unsigned int &r)
Definition: vpMe.h:271
void setThreshold(const double noise_threshold)
Definition: vpRobust.h:115
vpMeSite::vpMeSiteDisplayType selectDisplay
Definition: vpMeTracker.h:81
unsigned int getWidth() const
Definition: vpImage.h:229
void setIteration(const unsigned int iter)
Set iteration.
Definition: vpRobust.h:109
unsigned int getRange() const
Definition: vpMe.h:179
void eye()
Definition: vpMatrix.cpp:360
virtual void display(const vpImage< unsigned char > &I, vpColor col)=0
double ce
Value of cos(e).
Definition: vpMeEllipse.h:303
void set_ij(const double ii, const double jj)
Definition: vpImagePoint.h:189
static const vpColor blue
Definition: vpColor.h:186