Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
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
38
39void 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 }
130}
131
132void 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
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
241void 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
533END_VISP_NAMESPACE
unsigned int getCols() const
Definition vpArray2D.h:423
Implementation of column vector and the associated operations.
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 ...
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_ij(double ii, double jj)
void set_uv(double u, double v)
Definition of the vpImage class member functions.
Definition vpImage.h:131
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:175
void solveBySVD(const vpColVector &B, vpColVector &x) const
unsigned int nullSpace(vpMatrix &kerA, double svThreshold=1e-6) const
void leastSquareRobustEllipse(const double &um, const double &vm, unsigned int &k, vpColVector &w)
void computePointOnEllipse(const double angle, vpImagePoint &iP)
double m_alpha2
void leastSquareRobustCircle(const double &um, const double &vm, unsigned int &k, vpColVector &w)
double m_vc
Value of v coordinate of iPc.
void getParameters()
double m_uc
Value of u coordinate of iPc.
bool m_trackCircle
Track a circle (true) or an ellipse (false).
vpColVector m_K
double m_alphamin
std::list< double > m_angleList
Stores the value in increasing order of the angle on the ellipse for each vpMeSite.
bool m_trackArc
Track an arc of ellipse/circle (true) or a complete one (false).
double m_a
is the semi major axis of the ellipse.
unsigned int leastSquareRobust(const vpImage< unsigned char > &I)
double m_alpha1
void leastSquare(const vpImage< unsigned char > &I, const std::vector< vpImagePoint > &iP)
double m_b
is the semi minor axis of the ellipse.
double m_alphamax
unsigned int m_expectedDensity
Expected number of points to track along the ellipse.
double m_thresholdWeight
Threshold on the weights for the robust least square.
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:75
@ NO_SUPPRESSION
Point successfully tracked.
Definition vpMeSite.h:93
double m_ifloat
Subpixel coordinates along i of a site.
Definition vpMeSite.h:110
vpMeSiteState getState() const
Definition vpMeSite.h:306
double get_ifloat() const
Definition vpMeSite.h:212
double m_jfloat
Subpixel coordinates along j of a site.
Definition vpMeSite.h:112
double get_jfloat() const
Definition vpMeSite.h:218
unsigned int numberOfSignal()
vpMe * m_me
Moving edges initialisation parameters.
std::list< vpMeSite > m_meList
Contains an M-estimator and various influence function.
Definition vpRobust.h:84
@ TUKEY
Tukey influence function.
Definition vpRobust.h:89
Error that can be emitted by the vpTracker class and its derivatives.
@ fatalError
Tracker fatal error.