Visual Servoing Platform  version 3.6.1 under development (2024-10-18)
vpMeEllipse_least_square.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  */
30 
31 #include <visp3/core/vpConfig.h>
32 #include <visp3/me/vpMeEllipse.h>
33 #include <visp3/core/vpMatrixException.h>
34 #include <visp3/core/vpRobust.h>
35 #include <visp3/core/vpTrackingException.h>
36 
37 BEGIN_VISP_NAMESPACE
38 
39 void vpMeEllipse::leastSquare(const vpImage<unsigned char> &I, const std::vector<vpImagePoint> &iP)
40 {
41  double um = I.getWidth() / 2.;
42  double vm = I.getHeight() / 2.;
43  unsigned int n = static_cast<unsigned int>(iP.size());
44  const unsigned int index_0 = 0;
45  const unsigned int index_1 = 1;
46  const unsigned int index_2 = 2;
47  const unsigned int index_3 = 3;
48  const unsigned int index_4 = 4;
49  const unsigned int index_5 = 5;
50 
51  if (m_trackCircle) { // we track a circle
52  const unsigned int circleDims = 3;
53  if (n < circleDims) {
54  throw(vpException(vpException::dimensionError, "Not enough points to compute the circle"));
55  }
56  // System A x = b to be solved by least squares
57  // with A = (u v 1), b = (u^2 + v^2) and x = (2xc, 2yc, r^2-xc^2-yc^2)
58 
59  vpMatrix A(n, 3);
60  vpColVector b(n);
61 
62  for (unsigned int k = 0; k < n; ++k) {
63  // normalization so that (u,v) in [-1;1]
64  double u = (iP[k].get_u() - um) / um;
65  double v = (iP[k].get_v() - vm) / um; // um here to not deform the circle
66  A[k][index_0] = u;
67  A[k][index_1] = v;
68  A[k][index_2] = 1.0;
69  b[k] = (u * u) + (v * v);
70  }
71  vpColVector x(3);
72  x = A.solveBySVD(b);
73  // A circle is a particular ellipse. Going from x for circle to K for ellipse
74  // using inverse normalization to go back to pixel values
75  double ratio = vm / um;
76  m_K[index_0] = (m_K[index_1] = (1.0 / (um * um)));
77  m_K[index_2] = 0.0;
78  m_K[index_3] = -(1.0 + (x[index_0] / 2.0)) / um;
79  m_K[index_4] = -(ratio + (x[index_1] / 2.0)) / um;
80  m_K[index_5] = -x[index_2] + 1.0 + (ratio * ratio) + x[index_0] + (ratio * x[index_1]);
81  }
82  else { // we track an ellipse
83  const unsigned int npoints_min = 5;
84  if (n < npoints_min) {
85  throw(vpException(vpException::dimensionError, "Not enough points to compute the ellipse"));
86  }
87  // Homogeneous system A x = 0 ; x is the nullspace of A
88  // K0 u^2 + K1 v^2 + 2 K2 u v + 2 K3 u + 2 K4 v + K5 = 0
89  // A = (u^2 v^2 2uv 2u 2v 1), x = (K0 K1 K2 K3 K4 K5)^T
90 
91  // It would be a bad idea to solve the same system using A x = b where
92  // A = (u^2 v^2 2uv 2u 2v), b = (-1), x = (K0 K1 K2 K3 K4)^T since it
93  // cannot consider the case where the origin belongs to the ellipse.
94  // Another possibility would be to consider K0+K1=1 which is always valid,
95  // leading to the system A x = b where
96  // A = (u^2-v^2 2uv 2u 2v 1), b = (-v^2), x = (K0 K2 K3 K4 K5)^T
97 
98  vpMatrix A(n, 6);
99 
100  for (unsigned int k = 0; k < n; ++k) {
101  // Normalization so that (u,v) in [-1;1]
102  double u = (iP[k].get_u() - um) / um;
103  double v = (iP[k].get_v() - vm) / vm;
104  A[k][index_0] = u * u;
105  A[k][index_1] = v * v;
106  A[k][index_2] = 2.0 * u * v;
107  A[k][index_3] = 2.0 * u;
108  A[k][index_4] = 2.0 * v;
109  A[k][index_5] = 1.0;
110  }
111  vpMatrix KerA;
112  unsigned int dim = A.nullSpace(KerA, 1);
113  if (dim > 1) { // case with less than 5 independent points
114  throw(vpMatrixException(vpMatrixException::rankDeficient, "Linear system for computing the ellipse equation ill conditioned"));
115  }
116  unsigned int nbRows = m_K.getRows();
117  for (unsigned int i = 0; i < nbRows; ++i) {
118  m_K[i] = KerA[i][0];
119  }
120 
121  // inverse normalization
122  m_K[index_0] *= vm / um;
123  m_K[index_1] *= um / vm;
124  m_K[index_3] = (m_K[index_3] * vm) - (m_K[index_0] * um) - (m_K[index_2] * vm);
125  m_K[index_4] = (m_K[index_4] * um) - (m_K[index_1] * vm) - (m_K[index_2] * um);
126  m_K[index_5] = (m_K[index_5] * um * vm) - (m_K[index_0] * um * um) - (m_K[index_1] * vm * vm) -
127  (2.0 * m_K[index_2] * um * vm) - (2.0 * m_K[index_3] * um) - (2.0 * m_K[index_4] * vm);
128  }
129  getParameters();
130 }
131 
132 void vpMeEllipse::leastSquareRobustCircle(const double &um, const double &vm, unsigned int &k, vpColVector &w)
133 {
134  const unsigned int nos = numberOfSignal();
135  const unsigned int index_0 = 0;
136  const unsigned int index_1 = 1;
137  const unsigned int index_2 = 2;
138  const unsigned int index_3 = 3;
139  const unsigned int index_4 = 4;
140  const unsigned int index_5 = 5;
141 
142  // System A x = b to be solved by least squares
143  // with A = (u v 1), b = (u^2 + v^2) and x = (2xc, 2yc, r^2-xc^2-yc^2)
144 
145  // Note that the (nos-k) last rows of A, b, xp and yp are not used.
146  // Hopefully, this is not an issue.
147  vpMatrix A(nos, 3);
148  vpColVector b(nos);
149 
150  // Useful to compute the weights in the robust estimation
151  vpColVector xp(nos), yp(nos);
152  std::list<vpMeSite>::const_iterator end = m_meList.end();
153 
154  for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != end; ++it) {
155  vpMeSite p_me = *it;
156  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
157  // from (i,j) to (u,v) frame + normalization so that (u,v) in [-1;1]
158  double u = (p_me.get_jfloat() - um) / um;
159  double v = (p_me.get_ifloat() - vm) / um; // um to not deform the circle
160  A[k][index_0] = u;
161  A[k][index_1] = v;
162  A[k][index_2] = 1.0;
163  b[k] = (u * u) + (v * v);
164  // Useful to compute the weights in the robust estimation
165  xp[k] = p_me.get_jfloat();
166  yp[k] = p_me.get_ifloat();
167 
168  ++k;
169  }
170  }
171 
172  const unsigned int minRequiredNbMe = 3;
173  if (k < minRequiredNbMe) {
174  throw(vpException(vpException::dimensionError, "Not enough moving edges %d / %d to track the circle ",
175  k, m_meList.size()));
176  }
177 
178  vpRobust r;
179  r.setMinMedianAbsoluteDeviation(1.0); // Image noise in pixels for the algebraic distance
180 
181  unsigned int iter = 0;
182  double var = 1.0;
183  vpColVector x(3);
184  vpMatrix DA(k, 3);
185  vpColVector Db(k);
186  vpColVector xg_prev(2);
187  xg_prev = -10.0;
188 
189  // stop after 4 it or if cog variation between 2 it is more than 1 pixel
190  const unsigned int maxNbIter = 4;
191  const unsigned int widthDA = DA.getCols();
192  while ((iter < maxNbIter) && (var > 0.1)) {
193  for (unsigned int i = 0; i < k; ++i) {
194  for (unsigned int j = 0; j < widthDA; ++j) {
195  DA[i][j] = w[i] * A[i][j];
196  }
197  Db[i] = w[i] * b[i];
198  }
199  x = DA.solveBySVD(Db);
200 
201  // A circle is a particular ellipse. Going from x for circle to K for ellipse
202  // using inverse normalization to go back to pixel values
203  double ratio = vm / um;
204  m_K[index_0] = (m_K[index_1] = (1.0 / (um * um)));
205  m_K[index_2] = 0.0;
206  m_K[index_3] = -(1.0 + (x[index_0] / 2.0)) / um;
207  m_K[index_4] = -(ratio + (x[index_1] / 2.0)) / um;
208  m_K[index_5] = -x[index_2] + 1.0 + (ratio * ratio) + x[index_0] + (ratio * x[index_1]);
209 
210  getParameters();
211  vpColVector xg(2);
212  xg[0] = m_uc;
213  xg[1] = m_vc;
214  var = (xg - xg_prev).frobeniusNorm();
215  xg_prev = xg;
216 
217  vpColVector residu(k); // near to geometric distance in pixel
218  for (unsigned int i = 0; i < k; ++i) {
219  double x = xp[i];
220  double y = yp[i];
221  double sign = (m_K[index_0] * x * x) + (m_K[index_1] * y * y) + (2. * m_K[index_2] * x * y)
222  + (2. * m_K[index_3] * x) + (2. * m_K[index_4] * y) + m_K[index_5];
223  vpImagePoint ip1, ip2;
224  ip1.set_uv(x, y);
225  double ang = computeAngleOnEllipse(ip1);
226  computePointOnEllipse(ang, ip2);
227  // residu = 0 if point is exactly on the ellipse, not otherwise
228  if (sign > 0) {
229  residu[i] = vpImagePoint::distance(ip1, ip2);
230  }
231  else {
232  residu[i] = -vpImagePoint::distance(ip1, ip2);
233  }
234  }
235  r.MEstimator(vpRobust::TUKEY, residu, w);
236 
237  ++iter;
238  }
239 }
240 
241 void vpMeEllipse::leastSquareRobustEllipse(const double &um, const double &vm, unsigned int &k, vpColVector &w)
242 {
243  const unsigned int nos = numberOfSignal();
244  const unsigned int index_0 = 0;
245  const unsigned int index_1 = 1;
246  const unsigned int index_2 = 2;
247  const unsigned int index_3 = 3;
248  const unsigned int index_4 = 4;
249  const unsigned int index_5 = 5;
250  // Homogeneous system A x = 0 ; x is the nullspace of A
251  // K0 u^2 + K1 v^2 + 2 K2 u v + 2 K3 u + 2 K4 v + K5 = 0
252  // A = (u^2 v^2 2uv 2u 2v 1), x = (K0 K1 K2 K3 K4 K5)^T
253 
254  // It would be a bad idea to solve the same system using A x = b where
255  // A = (u^2 v^2 2uv 2u 2v), b = (-1), x = (K0 K1 K2 K3 K4)^T since it
256  // cannot consider the case where the origin belongs to the ellipse.
257  // Another possibility would be to consider K0+K1=1 which is always valid,
258  // leading to the system A x = b where
259  // A = (u^2-v^2 2uv 2u 2v 1), b = (-v^2), x = (K0 K2 K3 K4 K5)^T
260  const unsigned int nbColsA = 6;
261  vpMatrix A(nos, nbColsA);
262  // Useful to compute the weights in the robust estimation
263  vpColVector xp(nos), yp(nos);
264  std::list<vpMeSite>::const_iterator end = m_meList.end();
265 
266  for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != end; ++it) {
267  vpMeSite p_me = *it;
268  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
269  // from (i,j) to (u,v) frame + normalization so that (u,v) in [-1;1]
270  double u = (p_me.get_jfloat() - um) / um;
271  double v = (p_me.get_ifloat() - vm) / vm;
272  A[k][index_0] = u * u;
273  A[k][index_1] = v * v;
274  A[k][index_2] = 2.0 * u * v;
275  A[k][index_3] = 2.0 * u;
276  A[k][index_4] = 2.0 * v;
277  A[k][index_5] = 1.0;
278  // Useful to compute the weights in the robust estimation
279  xp[k] = p_me.get_jfloat();
280  yp[k] = p_me.get_ifloat();
281 
282  ++k;
283  }
284  }
285 
286  const unsigned int minRequiredMe = 5;
287  if (k < minRequiredMe) {
288  throw(vpException(vpException::dimensionError, "Not enough moving edges to track the ellipse"));
289  }
290 
291  vpRobust r;
292 
293  r.setMinMedianAbsoluteDeviation(1.0); // image noise in pixels for the geometrical distance
294  unsigned int iter = 0;
295  double var = 1.0;
296  vpMatrix DA(k, 6);
297  vpMatrix KerDA;
298  vpColVector xg_prev(2);
299  xg_prev = -10.0;
300 
301  // Stop after 4 iterations or if cog variation between 2 iterations is more than 0.1 pixel
302  const unsigned int maxIter = 4;
303  const unsigned int widthDA = DA.getCols();
304  while ((iter < maxIter) && (var > 0.1)) {
305  for (unsigned int i = 0; i < k; ++i) {
306  for (unsigned int j = 0; j < widthDA; ++j) {
307  DA[i][j] = w[i] * A[i][j];
308  }
309  }
310  unsigned int dim = DA.nullSpace(KerDA, 1);
311  if (dim > 1) { // case with less than 5 independent points
312  throw(vpMatrixException(vpMatrixException::rankDeficient, "Linear system for computing the ellipse equation ill conditioned"));
313  }
314 
315  const unsigned int nparam = 6;
316  for (unsigned int i = 0; i < nparam; ++i) {
317  m_K[i] = KerDA[i][0]; // norm(K) = 1
318  }
319 
320  // inverse normalization
321  m_K[index_0] *= vm / um;
322  m_K[index_1] *= um / vm;
323  m_K[index_3] = (m_K[index_3] * vm) - (m_K[0] * um) - (m_K[index_2] * vm);
324  m_K[index_4] = (m_K[index_4] * um) - (m_K[1] * vm) - (m_K[index_2] * um);
325  m_K[index_5] = (m_K[index_5] * um * vm) - (m_K[index_0] * um * um) - (m_K[index_1] * vm * vm)
326  - (2.0 * m_K[index_2] * um * vm) - (2.0 * m_K[index_3] * um) - (2.0 * m_K[index_4] * vm);
327 
328  getParameters(); // since a, b, and e are used just after
329  vpColVector xg(2);
330  xg[0] = m_uc;
331  xg[1] = m_vc;
332  var = (xg - xg_prev).frobeniusNorm();
333  xg_prev = xg;
334 
335  vpColVector residu(k);
336  for (unsigned int i = 0; i < k; ++i) {
337  double x = xp[i];
338  double y = yp[i];
339  double sign = (m_K[0] * x * x) + (m_K[1] * y * y) + (2. * m_K[2] * x * y) + (2. * m_K[3] * x) + (2. * m_K[4] * y) + m_K[5];
340  vpImagePoint ip1, ip2;
341  ip1.set_uv(x, y);
342  double ang = computeAngleOnEllipse(ip1);
343  computePointOnEllipse(ang, ip2);
344  // residu = 0 if point is exactly on the ellipse, not otherwise
345  if (sign > 0) {
346  residu[i] = vpImagePoint::distance(ip1, ip2);
347  }
348  else {
349  residu[i] = -vpImagePoint::distance(ip1, ip2);
350  }
351  }
352  r.MEstimator(vpRobust::TUKEY, residu, w);
353 
354  ++iter;
355  }
356 }
357 
359 {
360  double um = I.getWidth() / 2.;
361  double vm = I.getHeight() / 2.;
362 
363  const unsigned int nos = numberOfSignal();
364  unsigned int k = 0; // count the number of tracked MEs
365 
366  vpColVector w(nos);
367  w = 1.0;
368  // Note that the (nos-k) last rows of w are not used. Hopefully, this is not an issue.
369 
370  if (m_trackCircle) { // we track a circle
371  leastSquareRobustCircle(um, vm, k, w);
372  }
373  else { // we track an ellipse
374  leastSquareRobustEllipse(um, vm, k, w);
375  } // end of case ellipse
376 
377  // Remove bad points and outliers from the lists
378  // Modify the angle to order the list
379  double previous_ang = -4.0 * M_PI;
380  k = 0;
381  std::list<double>::iterator angleList = m_angleList.begin();
382  std::list<vpMeSite>::iterator end = m_meList.end();
383  std::list<vpMeSite>::iterator meList = m_meList.begin();
384  while (meList != end) {
385  vpMeSite p_me = *meList;
386  if (p_me.getState() != vpMeSite::NO_SUPPRESSION) {
387  // points not selected as me
388  meList = m_meList.erase(meList);
389  angleList = m_angleList.erase(angleList);
390  }
391  else {
392  if (w[k] < m_thresholdWeight) { // outlier
393  meList = m_meList.erase(meList);
394  angleList = m_angleList.erase(angleList);
395  }
396  else { // good point
397  double ang = *angleList;
398  vpImagePoint iP;
399  iP.set_ij(p_me.m_ifloat, p_me.m_jfloat);
400  double new_ang = computeAngleOnEllipse(iP);
401  if ((new_ang - ang) > M_PI) {
402  new_ang -= 2.0 * M_PI;
403  }
404  else if ((ang - new_ang) > M_PI) {
405  new_ang += 2.0 * M_PI;
406  }
407  previous_ang = new_ang;
408  *angleList = new_ang;
409  ++meList;
410  ++angleList;
411  }
412  ++k; // k contains good points and outliers (used for w[k])
413  }
414  }
415 
416  if (m_meList.size() != m_angleList.size()) {
417  // Should never occur
418  throw(vpTrackingException(vpTrackingException::fatalError, "Lists are not coherent in vpMeEllipse::leastSquareRobust(): nb MEs %ld, nb ang %ld",
419  m_meList.size(), m_angleList.size()));
420  }
421 
422  // Manage the list so that all new angles belong to [0;2Pi]
423  bool nbdeb = false;
424  std::list<double> finAngle;
425  finAngle.clear();
426  std::list<vpMeSite> finMe;
427  finMe.clear();
428  std::list<double>::iterator debutAngleList;
429  std::list<vpMeSite>::iterator debutMeList;
430  angleList = m_angleList.begin();
431  meList = m_meList.begin();
432  end = m_meList.end();
433  while (meList != end) {
434  vpMeSite p_me = *meList;
435  double ang = *angleList;
436 
437  // Move these ones to another list to be added at the end
438  if (ang < m_alpha1) {
439  ang += 2.0 * M_PI;
440  angleList = m_angleList.erase(angleList);
441  finAngle.push_back(ang);
442  meList = m_meList.erase(meList);
443  finMe.push_back(p_me);
444  }
445  // Moved at the beginning of the list
446  else if (ang > m_alpha2) {
447  ang -= 2.0 * M_PI;
448  angleList = m_angleList.erase(angleList);
449  meList = m_meList.erase(meList);
450  if (!nbdeb) {
451  m_angleList.push_front(ang);
452  debutAngleList = m_angleList.begin();
453  ++debutAngleList;
454 
455  m_meList.push_front(p_me);
456  debutMeList = m_meList.begin();
457  ++debutMeList;
458 
459  nbdeb = true;
460  }
461  else {
462  debutAngleList = m_angleList.insert(debutAngleList, ang);
463  ++debutAngleList;
464  debutMeList = m_meList.insert(debutMeList, p_me);
465  ++debutMeList;
466  }
467  }
468  else {
469  ++angleList;
470  ++meList;
471  }
472  }
473  // Fuse the lists
474  angleList = m_angleList.end();
475  m_angleList.splice(angleList, finAngle);
476  meList = m_meList.end();
477  m_meList.splice(meList, finMe);
478 
479  unsigned int numberOfGoodPoints = 0;
480  previous_ang = -4.0 * M_PI;
481 
482  // Perimeter of the ellipse using Ramanujan formula
483  double perim = M_PI * ((3.0 * (m_a + m_b)) - sqrt(((3.0 * m_a) + m_b) * (m_a + (3.0 * m_b))));
484  unsigned int nb_pt = static_cast<unsigned int>(floor(perim / m_me->getSampleStep()));
485  double incr = (2.0 * M_PI) / nb_pt;
486  // Update of the expected density
487  if (!m_trackArc) { // number of points for a complete ellipse
488  m_expectedDensity = nb_pt;
489  }
490  else { // number of points for an arc of ellipse
491  m_expectedDensity *= static_cast<unsigned int>(floor((perim / m_me->getSampleStep()) * ((m_alpha2 - m_alpha1) / (2.0 * M_PI))));
492  }
493 
494  // Keep only the points in the interval [alpha1 ; alpha2]
495  // and those that are not too close
496  angleList = m_angleList.begin();
497  end = m_meList.end();
498  meList = m_meList.begin();
499  while (meList != end) {
500  vpMeSite p_me = *meList;
501  double new_ang = *angleList;
502  if ((new_ang >= m_alpha1) && (new_ang <= m_alpha2)) {
503  if ((new_ang - previous_ang) >= (0.6 * incr)) {
504  previous_ang = new_ang;
505  ++numberOfGoodPoints;
506  ++meList;
507  ++angleList;
508  }
509  else {
510  meList = m_meList.erase(meList);
511  angleList = m_angleList.erase(angleList);
512  }
513  }
514  else { // point not in the interval [alpha1 ; alpha2]
515  meList = m_meList.erase(meList);
516  angleList = m_angleList.erase(angleList);
517  }
518  }
519 
520  if ((m_meList.size() != numberOfGoodPoints) || (m_angleList.size() != numberOfGoodPoints)) {
521  // Should never occur
522  throw(vpTrackingException(vpTrackingException::fatalError, "Lists are not coherent at the end of vpMeEllipse::leastSquareRobust(): nb goog MEs %d and %ld, nb ang %ld",
523  numberOfGoodPoints, m_meList.size(), m_angleList.size()));
524  }
525 
526  // set extremities of the angle list
527  m_alphamin = m_angleList.front();
528  m_alphamax = m_angleList.back();
529 
530  return numberOfGoodPoints;
531 }
532 
533 END_VISP_NAMESPACE
unsigned int getCols() const
Definition: vpArray2D.h:337
unsigned int getRows() const
Definition: vpArray2D.h:347
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_ij(double ii, double jj)
Definition: vpImagePoint.h:320
void set_uv(double u, double v)
Definition: vpImagePoint.h:357
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getHeight() const
Definition: vpImage.h:181
error that can be emitted by the vpMatrix class and its derivatives
@ rankDeficient
Rank deficient.
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
void solveBySVD(const vpColVector &B, vpColVector &x) const
unsigned int nullSpace(vpMatrix &kerA, double svThreshold=1e-6) const
Definition: vpMatrix.cpp:1491
void leastSquareRobustEllipse(const double &um, const double &vm, unsigned int &k, vpColVector &w)
void computePointOnEllipse(const double angle, vpImagePoint &iP)
double m_alpha2
Definition: vpMeEllipse.h:437
void leastSquareRobustCircle(const double &um, const double &vm, unsigned int &k, vpColVector &w)
double m_vc
Value of v coordinate of iPc.
Definition: vpMeEllipse.h:461
void getParameters()
double m_uc
Value of u coordinate of iPc.
Definition: vpMeEllipse.h:459
bool m_trackCircle
Track a circle (true) or an ellipse (false).
Definition: vpMeEllipse.h:473
vpColVector m_K
Definition: vpMeEllipse.h:409
double m_alphamin
Definition: vpMeEllipse.h:453
std::list< double > m_angleList
Stores the value in increasing order of the angle on the ellipse for each vpMeSite.
Definition: vpMeEllipse.h:443
bool m_trackArc
Track an arc of ellipse/circle (true) or a complete one (false).
Definition: vpMeEllipse.h:475
double m_a
is the semi major axis of the ellipse.
Definition: vpMeEllipse.h:413
unsigned int leastSquareRobust(const vpImage< unsigned char > &I)
double m_alpha1
Definition: vpMeEllipse.h:432
void leastSquare(const vpImage< unsigned char > &I, const std::vector< vpImagePoint > &iP)
double m_b
is the semi minor axis of the ellipse.
Definition: vpMeEllipse.h:415
double m_alphamax
Definition: vpMeEllipse.h:457
unsigned int m_expectedDensity
Expected number of points to track along the ellipse.
Definition: vpMeEllipse.h:469
double m_thresholdWeight
Threshold on the weights for the robust least square.
Definition: vpMeEllipse.h:448
double computeAngleOnEllipse(const vpImagePoint &pt) const
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
Definition: vpMeSite.h:68
@ NO_SUPPRESSION
Point successfully tracked.
Definition: vpMeSite.h:86
double m_ifloat
Subpixel coordinates along i of a site.
Definition: vpMeSite.h:103
vpMeSiteState getState() const
Definition: vpMeSite.h:283
double get_ifloat() const
Definition: vpMeSite.h:195
double m_jfloat
Subpixel coordinates along j of a site.
Definition: vpMeSite.h:105
double get_jfloat() const
Definition: vpMeSite.h:201
unsigned int numberOfSignal()
Definition: vpMeTracker.cpp:94
vpMe * m_me
Moving edges initialisation parameters.
Definition: vpMeTracker.h:313
std::list< vpMeSite > m_meList
Definition: vpMeTracker.h:311
double getSampleStep() const
Definition: vpMe.h:275
Contains an M-estimator and various influence function.
Definition: vpRobust.h:84
@ TUKEY
Tukey influence function.
Definition: vpRobust.h:89
void MEstimator(const vpRobustEstimatorType method, const vpColVector &residues, vpColVector &weights)
Definition: vpRobust.cpp:130
void setMinMedianAbsoluteDeviation(double mad_min)
Definition: vpRobust.h:136
Error that can be emitted by the vpTracker class and its derivatives.
@ fatalError
Tracker fatal error.