Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpMeLine.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Moving edges.
32 */
33
38
39#include <algorithm> // (std::min)
40#include <cmath> // std::fabs
41#include <limits> // numeric_limits
42#include <stdlib.h>
43#include <visp3/core/vpDebug.h>
44#include <visp3/core/vpImagePoint.h>
45#include <visp3/core/vpMath.h>
46#include <visp3/core/vpRobust.h>
47#include <visp3/core/vpTrackingException.h>
48#include <visp3/core/vpMatrixException.h>
49#include <visp3/me/vpMe.h>
50#include <visp3/me/vpMeLine.h>
51#include <visp3/me/vpMeSite.h>
52#include <visp3/me/vpMeTracker.h>
53
54#define INCR_MIN 1
55
57
66 void vpMeLine::project(double a, double b, double c, const vpMeSite &P, vpImagePoint &iP)
67{
68 const double i = P.m_ifloat;
69 const double j = P.m_jfloat;
70 double ip, jp;
71
72 double norm = a*a + b*b; // cannot be 0
73 double cross = b*i - a*j;
74 ip = (b*cross - a*c)/norm;
75 jp = (-a*cross - b*c)/norm;
76
77 iP.set_i(ip);
78 iP.set_j(jp);
79}
80
82 : m_rho(0.), m_theta(0.), m_delta(0.), m_sign(1), m_a(0.), m_b(0.), m_c(0.)
83{ }
84
85vpMeLine::vpMeLine(const vpMeLine &meline) : vpMeTracker(meline)
86{
87 *this = meline;
88}
89
91{
92 m_meList.clear();
93}
94
96{
97 m_rho = meline.m_rho;
98 m_theta = meline.m_theta;
99 m_delta = meline.m_delta;
100 m_sign = meline.m_sign;
101
102 m_a = meline.m_a;
103 m_b = meline.m_b;
104 m_c = meline.m_c;
105
106 m_PExt[0] = meline.m_PExt[0];
107 m_PExt[1] = meline.m_PExt[1];
108
109 return *this;
110}
111
112void vpMeLine::sample(const vpImage<unsigned char> &I, bool doNotTrack)
113{
114 (void)doNotTrack;
115 if (!m_me) {
116 vpDERROR_TRACE(2, "Tracking error: Moving edges not initialized");
117 throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
118 }
119
120 double sampleStep = fabs(m_me->getSampleStep());
121 if (sampleStep <= std::numeric_limits<double>::epsilon()) {
122 vpERROR_TRACE("function called with sample step = 0");
123 throw(vpTrackingException(vpTrackingException::fatalError, "sample step = 0"));
124 }
125
126 // i, j portions of the line_p
127 double diffsi = m_PExt[1].m_ifloat - m_PExt[0].m_ifloat;
128 double diffsj = m_PExt[1].m_jfloat - m_PExt[0].m_jfloat;
129
130 double length_p = sqrt((vpMath::sqr(diffsi) + vpMath::sqr(diffsj)));
131 if (length_p < (2.0 * sampleStep)) {
132 throw(vpTrackingException(vpTrackingException::fatalError, "Points too close together to define a line"));
133 }
134 // number of samples along line_p
135 double n_sample = length_p / sampleStep;
136
137 double stepi = diffsi / n_sample;
138 double stepj = diffsj / n_sample;
139
140 // Choose starting point
141 double is = m_PExt[0].m_ifloat;
142 double js = m_PExt[0].m_jfloat;
143
144 // Delete old list
145 m_meList.clear();
146
147 // sample positions at i*m_me->getSampleStep() interval along the line_p, starting at PSiteExt[0]
148 int nbrows = static_cast<int>(I.getHeight());
149 int nbcols = static_cast<int>(I.getWidth());
150 const double marginRatio = m_me->getThresholdMarginRatio();
151
152 for (int i = 0; i <= vpMath::round(n_sample); ++i) {
153 vpImagePoint iP;
154 iP.set_ij(is, js);
155 if (!outOfImage(iP, 5, nbrows, nbcols)) {
156 unsigned int is_uint = static_cast<unsigned int>(is);
157 unsigned int js_uint = static_cast<unsigned int>(js);
158 if (inRoiMask(m_mask, is_uint, js_uint) && inMeMaskCandidates(m_maskCandidates, is_uint, js_uint)) {
159 vpMeSite pix;
160 pix.init(is, js, m_delta, 0, m_sign);
163 double convolution = pix.convolution(I, m_me);
164 double contrastThreshold = fabs(convolution) * marginRatio;
165 pix.setContrastThreshold(contrastThreshold, *m_me);
166 if (vpDEBUG_ENABLE(3)) {
168 }
169 m_meList.push_back(pix);
170 }
171 }
172 is += stepi;
173 js += stepj;
174 }
175}
176
177void vpMeLine::display(const vpImage<unsigned char> &I, const vpColor &color, unsigned int thickness)
178{
179 vpMeLine::displayLine(I, m_PExt[0], m_PExt[1], m_meList, m_a, m_b, m_c, color, thickness);
180}
181
182void vpMeLine::display(const vpImage<vpRGBa> &I, const vpColor &color, unsigned int thickness)
183{
184 vpMeLine::displayLine(I, m_PExt[0], m_PExt[1], m_meList, m_a, m_b, m_c, color, thickness);
185}
186
188{
189 vpImagePoint ip1, ip2;
190
192
193 std::cout << "Click on the line first point..." << std::endl;
194 while (vpDisplay::getClick(I, ip1) != true) { }
195
198 std::cout << "Click on the line second point..." << std::endl;
199 while (vpDisplay::getClick(I, ip2) != true) { }
200
203
204 initTracking(I, ip1, ip2);
205}
206
208{
209 const unsigned int nos = numberOfSignal(); // number of MEs correctly tracked
210
211 if (m_meList.size() <= 2 || nos <= 2) {
213 }
214
215 const double nbr = I.getHeight() / 2.;
216 const double nbc = I.getWidth() / 2.;
217 unsigned int k = 0; // number of good points (should be numberOfSignal
218 // at the end of the first loop and then all after)
219
220 // System A x = 0 to be solved by least squares
221 // with A = (u v 1) and x = (au, bu, cu)
222
223 // Note that the (nos-k) last rows of A, xp and yp are not used.
224 // Hopefully, this is not an issue.
225 vpMatrix A(nos, 3);
226
227 // Useful to compute the weights in the robust estimation
228 vpColVector xp(nos), yp(nos);
229 std::list<vpMeSite>::const_iterator end = m_meList.end();
230
231 for (std::list<vpMeSite>::const_iterator it = m_meList.begin(); it != end; ++it) {
232 vpMeSite p_me = *it;
233 if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
234 // From (i,j) to (u,v) frame so that (u,v) in [-1;1]
235 double u = (p_me.m_ifloat - nbr) / nbr;
236 double v = (p_me.m_jfloat - nbc) / nbc;
237 A[k][0] = u;
238 A[k][1] = v;
239 A[k][2] = 1.0;
240 // Useful to compute the weights in the robust estimation
241 xp[k] = p_me.m_ifloat;
242 yp[k] = p_me.m_jfloat;
243 ++k;
244 }
245 }
246
247 const unsigned int minRequiredNbMe = 2;
248 if (k < minRequiredNbMe) {
249 throw(vpException(vpException::dimensionError, "Not enough moving edges %d / %d to track the line ",
250 k, m_meList.size()));
251 }
252
253 vpRobust r;
254 r.setMinMedianAbsoluteDeviation(1.0); // Image noise in pixels for the distance from points to line
255
256 unsigned int iter = 0;
257 double var = 10.0;
258 vpColVector x(3);
259 vpMatrix DA(k, 3);
260 vpMatrix KerDA;
261 vpColVector w(k);
262 w = 1.0;
263 vpColVector x_prev(3);
264 x_prev = 0.0;
265
266 // stop after 4 it or if variation between 2 it is less than 1 pixel
267 const unsigned int maxNbIter = 4;
268 const unsigned int widthDA = DA.getCols();
269 while ((iter < maxNbIter) && (var > 0.1)) {
270 for (unsigned int i = 0; i < k; ++i) {
271 for (unsigned int j = 0; j < widthDA; ++j) {
272 DA[i][j] = w[i] * A[i][j];
273 }
274 }
275 unsigned int dim = DA.nullSpace(KerDA, 1);
276 if (dim > 1) { // case with less than 2 independent points
277 throw(vpMatrixException(vpMatrixException::rankDeficient, "Linear system for computing the line equation ill conditioned"));
278 }
279
280 for (unsigned int i = 0; i < 3; ++i) {
281 x[i] = KerDA[i][0]; // norm(x) = 1
282 }
283
284 // using inverse normalization to go back to pixel values
285 double a, b, c;
286 a = x[0]/nbr;
287 b = x[1]/nbc;
288 c = x[2] - x[0] - x[1];
289 // normalization such that a^2+b^2 = 1
290 // important to compute the distance between points and line
291 const double norm = 1.0/sqrt(vpMath::sqr(a)+vpMath::sqr(b));
292 x[0] = a * norm;
293 x[1] = b * norm;
294 x[2] = c * norm;
295
296 var = (x - x_prev).frobeniusNorm();
297 x_prev = x;
298
299 vpColVector residu(k); // distance from points to line
300 for (unsigned int i = 0; i < k; ++i) {
301 residu[i] = x[0] * xp[i] + x[1] * yp[i] + x[2];
302 }
303 r.MEstimator(vpRobust::TUKEY, residu, w);
304
305 ++iter;
306 }
307 m_a = x[0];
308 m_b = x[1];
309 m_c = x[2];
310
311 // remove all bad points in the list
312 unsigned int i = 0;
313 end = m_meList.end();
314 for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != end;) {
315 vpMeSite p_me = *it;
316 if (p_me.getState() != vpMeSite::NO_SUPPRESSION) {
317 it = m_meList.erase(it);
318 }
319 else {
320 // remove outliers
321 if (w[i] < 0.2) { // FS: m_thresholdWeight pour vpMeEllipse
322 it = m_meList.erase(it);
323 }
324 else { // good point
325 ++it;
326 }
327 ++i;
328 }
329 }
330}
331
333{
334 // 1. We do what concerns straight lines
335 // Extremity points
336 double id1, jd1, id2, jd2;
337 id1 = ip1.get_i();
338 jd1 = ip1.get_j();
339 id2 = ip2.get_i();
340 jd2 = ip2.get_j();
341
342 m_PExt[0].m_ifloat = id1;
343 m_PExt[0].m_jfloat = jd1;
344 m_PExt[1].m_ifloat = id2;
345 m_PExt[1].m_jfloat = jd2;
346
347 m_delta = atan2((jd2 - jd1), (id1 - id2));
348
349 sample(I);
350
351 // 2. We call what is not specific
353}
354
356{
357 m_PExt[0] = m_meList.front();
358 m_PExt[1] = m_meList.back();
359}
360
362{
363 if (!m_me) {
364 throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
365 }
366
367 if (std::fabs(m_me->getSampleStep()) <= std::numeric_limits<double>::epsilon()) {
368 throw(vpTrackingException(vpTrackingException::fatalError, "vpMeLine::plugHoles() called with sample step = 0"));
369 }
370
371 int nbrows = static_cast<int>(I.getHeight());
372 int nbcols = static_cast<int>(I.getWidth());
373
374 unsigned int memory_range = m_me->getRange();
375 m_me->setRange(1);
376
377 const double marginRatio = m_me->getThresholdMarginRatio();
378
379 unsigned int nb_added_points = 0;
380
381 std::list<vpMeSite>::iterator meList = m_meList.begin();
382 std::list<vpMeSite>::const_iterator end = m_meList.end();
383
384 vpImagePoint ip1, ip2;
385 getExtremities(ip1, ip2);
386 // To add as many points as possible
387 // i, j portions of the line_p
388 const double sampleStep = fabs(m_me->getSampleStep());
389 double diffsi = m_PExt[1].m_ifloat - m_PExt[0].m_ifloat;
390 double diffsj = m_PExt[1].m_jfloat - m_PExt[0].m_jfloat;
391 double length = sqrt((vpMath::sqr(diffsi) + vpMath::sqr(diffsj)));
392 double stepi = diffsi * sampleStep / length;
393 double stepj = diffsj * sampleStep / length;
394
395 vpMeSite pix1 = *meList;
396 project(m_a, m_b, m_c, pix1, ip1);
397 ++meList;
398 while (meList != end) {
399 vpMeSite pix2 = *meList;
400 project(m_a, m_b, m_c, pix2, ip2);
401
402 double dist = sqrt(vpMath::sqr(ip1.get_i() - ip2.get_i())
403 + vpMath::sqr(ip1.get_j() - ip2.get_j()));
404 const unsigned int n_sample = static_cast<unsigned int>(floor(dist / sampleStep));
405 if (n_sample > 1) {
406 double is = ip1.get_i();
407 double js = ip1.get_j();
408 for (unsigned int i = 0; i<n_sample; ++i) {
409 vpImagePoint iP;
410 iP.set_ij(is, js);
411 if (!outOfImage(iP, 5, nbrows, nbcols)) {
412 unsigned int is_uint = static_cast<unsigned int>(is);
413 unsigned int js_uint = static_cast<unsigned int>(js);
414 if (inRoiMask(m_mask, is_uint, js_uint) && inMeMaskCandidates(m_maskCandidates, is_uint, js_uint)) {
415 vpMeSite pix;
416 pix.init(is, js, m_delta, 0, m_sign);
419 double convolution = pix.convolution(I, m_me);
420 double contrastThreshold = fabs(convolution) * marginRatio;
421 pix.setContrastThreshold(contrastThreshold, *m_me);
422 pix.track(I, m_me, false);
423 if (pix.getState() == vpMeSite::NO_SUPPRESSION) { // good point
424 nb_added_points++;
425 m_meList.insert(meList, pix);
426 }
427 if (vpDEBUG_ENABLE(3)) {
429 }
430 }
431 }
432 is += stepi;
433 js += stepj;
434 }
435 }
436 pix1 = pix2;
437 ip1 = ip2;
438 ++meList;
439 }
440 m_me->setRange(memory_range);
441
442 return(nb_added_points);
443}
444
446{
447 int nbrows = static_cast<int>(I.getHeight());
448 int nbcols = static_cast<int>(I.getWidth());
449
450 // Point extremities strictly on the straight line
451 vpImagePoint ip1, ip2;
452 getExtremities(ip1, ip2);
453 double id1 = ip1.get_i();
454 double jd1 = ip1.get_j();
455 double id2 = ip2.get_i();
456 double jd2 = ip2.get_j();
457
458 // i, j portions of the line_p
459 double diffsi = id2 - id1;
460 double diffsj = jd2 - jd1;
461 double s = sqrt(vpMath::sqr(diffsi) + vpMath::sqr(diffsj));
462
463 double sample_step = static_cast<double>(m_me->getSampleStep());
464
465 double di = diffsi * sample_step / s; // pas de risque de /0 car d(P1,P2) >0
466 double dj = diffsj * sample_step / s;
467
468 vpMeSite P;
469 P.init(static_cast<int>(id1), static_cast<int>(jd1), m_delta, 0, m_sign);
471 const double marginRatio = m_me->getThresholdMarginRatio();
472
473 unsigned int memory_range = m_me->getRange();
474 m_me->setRange(1);
475
476 unsigned int nb_added_points = 0;
477
478 // Try to add at max 3 points along first extremity
479 // (could be a little bit more or less)
480 for (int i = 0; i < 3; i++) {
481 id1 -= di;
482 jd1 -= dj;
483 vpImagePoint iP;
484 iP.set_ij(id1, jd1);
485
486 // First test to ensure that iP coordinates are > 0 before casting to unsigned int
487 if (!outOfImage(iP, 5, nbrows, nbcols)) {
488 unsigned int is_uint = static_cast<unsigned int>(id1);
489 unsigned int js_uint = static_cast<unsigned int>(jd1);
490 // Note here that it is more efficient to cast the coordinates to unsigned int instead of using
491 // directly the image point iP that contains floating point coordinates.
492 // It allows to makes less tests.
493 if (inRoiMask(m_mask, is_uint, js_uint) && inMeMaskCandidates(m_maskCandidates, is_uint, js_uint)) {
494 // ajout
495 P.m_ifloat = id1;
496 P.m_i = static_cast<int>(id1);
497 P.m_jfloat = jd1;
498 P.m_j = static_cast<int>(jd1);
499 double convolution = P.convolution(I, m_me);
500 double contrastThreshold = fabs(convolution) * marginRatio;
501 P.setContrastThreshold(contrastThreshold, *m_me);
502 // fin ajout
503 P.track(I, m_me, false);
505 m_meList.push_front(P);
506 nb_added_points++;
507 if (vpDEBUG_ENABLE(3)) {
509 }
510 }
511 else {
512 if (vpDEBUG_ENABLE(3)) {
514 }
515 }
516 }
517 }
518 }
519
520 for (int i = 0; i < 3; i++) {
521 id2 += di;
522 jd2 += dj;
523
524 vpImagePoint iP;
525 iP.set_i(id2);
526 iP.set_j(jd2);
527
528 // First test to ensure that iP coordinates are > 0 before casting to unsigned int
529 if (!outOfImage(iP, 5, nbrows, nbcols)) {
530 unsigned int is_uint = static_cast<unsigned int>(id2);
531 unsigned int js_uint = static_cast<unsigned int>(jd2);
532 if (inRoiMask(m_mask, is_uint, js_uint) && inMeMaskCandidates(m_maskCandidates, is_uint, js_uint)) {
533 P.m_ifloat = id2;
534 P.m_i = static_cast<int>(id2);
535 P.m_jfloat = jd2;
536 P.m_j = static_cast<int>(jd2);
537 double convolution = P.convolution(I, m_me);
538 double contrastThreshold = fabs(convolution) * marginRatio;
539 P.setContrastThreshold(contrastThreshold, *m_me);
540 P.track(I, m_me, false);
542 m_meList.push_back(P);
543 nb_added_points++;
544 if (vpDEBUG_ENABLE(3)) {
546 }
547 }
548 else {
549 if (vpDEBUG_ENABLE(3)) {
551 }
552 }
553 }
554 }
555 }
556
557 m_me->setRange(memory_range);
558 return(nb_added_points);
559}
560
562{
563 if (!m_me) {
564 throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
565 }
566
567 // Good points are in m_meList
568 const unsigned int minNbGoodPoints = 4;
569 if (m_meList.size() <= minNbGoodPoints) {
570 // We are confident in the 2 good MEs at extremities
571 double id1, jd1, id2, jd2;
572 id1 = m_PExt[0].m_ifloat;
573 jd1 = m_PExt[0].m_jfloat;
574 id2 = m_PExt[1].m_ifloat;
575 jd2 = m_PExt[1].m_jfloat;
576 // m_delta is the angle of the line used for the ME
577 m_delta = atan2((jd2 - jd1), (id1 - id2));
578
579 sample(I);
580 // We call what is not specific
582 // Tracking after resampling
584
585 // Least square estimation of the straight line parameters
586 leastSquare(I);
587
588 setExtremities(); // useful if a getExtremities is done
589
590 }
591}
592
594{
595 vpMeSite p_me;
596
597 // Update delta
598 m_delta = atan2(m_a, m_b);
599 std::list<vpMeSite>::const_iterator end = m_meList.end();
600 for (std::list<vpMeSite>::iterator it = m_meList.begin(); it != end; ++it) {
601 p_me = *it;
602 p_me.setAlpha(m_delta);
603 *it = p_me;
604 }
605}
606
608{
609 vpCDEBUG(1) << "begin vpMeLine::track()" << std::endl;
610
612
613 // 3. Back to straight lines
614
615 // Least squares estimation of the parameters of the line
616 leastSquare(I);
617
618 // Try adding adding new points in holes
619 unsigned int nb = plugHoles(I);
620 // Try adding adding new points at both extremities
621 nb += seekExtremities(I);
622 if (nb > 0) {
623 leastSquare(I);
624 }
625 setExtremities(); // useful for resample() or if a getExtremities() is called
626
627 // Resampling if necessary
628 reSample(I);
629
630 // updates the delta angle for each point in the list
631 updateDelta();
632
633 if (vpDEBUG_ENABLE(2)) {
637 }
639}
640
641void vpMeLine::update_indices(double theta, int i, int j, int incr, int &i1, int &i2, int &j1, int &j2)
642{
643 i1 = static_cast<int>(i + cos(theta) * incr);
644 j1 = static_cast<int>(j + sin(theta) * incr);
645
646 i2 = static_cast<int>(i - cos(theta) * incr);
647 j2 = static_cast<int>(j - sin(theta) * incr);
648}
649
654{
655 // Vote using all MEs in which direction is the contrast
656 unsigned int nb_pos = 0;
657 unsigned int nb_neg = 0;
658
659 std::list<vpMeSite>::const_iterator it = m_meList.begin();
660 std::list<vpMeSite>::const_iterator end = m_meList.end();
661
662 for (; it != end; ++it) {
663 vpMeSite p_me = *it;
664 if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
665 if (p_me.m_mask_sign > 0) {
666 nb_pos++;
667 }
668 else {
669 nb_neg++;
670 }
671 }
672 }
673 // select the index for the first good ME (should be the first one)
674 it = m_meList.begin();
675 vpMeSite p_me = *it;
676 while (p_me.getState() != vpMeSite::NO_SUPPRESSION) {
677 ++it;
678 p_me = *it;
679 }
680 double ang = vpMath().rad(static_cast<double>(p_me.getIndex()));
681 if (nb_neg > nb_pos) {
682 ang += M_PI;
683 }
684
685 double Mx = -cos(ang); // point from contrast expressed in (i,j) frame
686 double My = sin(ang);
687
688 double Px = m_a; // first possibility for theta expressed as a point
689 double Py = m_b;
690
691 double d1 = (Px-Mx)*(Px-Mx) + (Py-My)*(Py-My);
692 double d2 = (-Px-Mx)*(-Px-Mx) + (-Py-My)*(-Py-My); //second possibility
693 if (d1 < d2) {
694 m_theta = atan2(m_b, m_a); // first possibility selected
695 m_rho = -m_c;
696 }
697 else {
698 m_theta = atan2(-m_b, -m_a); // second possibility selected
699 m_rho = m_c;
700 }
701}
702
704{
705 /* Return the coordinates of the two extremities of the line*/
706
707 const vpMeSite P0 = m_meList.front();
708 project(m_a, m_b, m_c, P0, ip1);
709
710 const vpMeSite P1 = m_meList.back();
711 project(m_a, m_b, m_c, P1, ip2);
712}
713
714bool vpMeLine::intersection(const vpMeLine &line1, const vpMeLine &line2, vpImagePoint &iP)
715{
716 double a1 = line1.m_a;
717 double b1 = line1.m_b;
718 double c1 = line1.m_c;
719 double a2 = line2.m_a;
720 double b2 = line2.m_b;
721 double c2 = line2.m_c;
722
723 double det = a1*b2 - a2*b1;
724
725 if (std::fabs(det) <= std::numeric_limits<double>::epsilon()) {
726 std::cout << "!!!!!!!!!!!!! Problem : Lines are parallel !!!!!!!!!!!!!" << std::endl;
727 return false;
728 }
729 double i = (c2*b1 - c1*b2)/det;
730 double j = (a2*c1 - a1*c2)/det;
731
732 iP.set_i(i);
733 iP.set_j(j);
734 return true;
735}
736
737#ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
752void vpMeLine::display(const vpImage<unsigned char> &I, const vpMeSite &PExt1, const vpMeSite &PExt2, const double &A,
753 const double &B, const double &C, const vpColor &color, unsigned int thickness)
754{
755 vpMeLine::displayLine(I, PExt1, PExt2, A, B, C, color, thickness);
756}
757
772void vpMeLine::display(const vpImage<vpRGBa> &I, const vpMeSite &PExt1, const vpMeSite &PExt2, const double &A,
773 const double &B, const double &C, const vpColor &color, unsigned int thickness)
774{
775 vpMeLine::displayLine(I, PExt1, PExt2, A, B, C, color, thickness);
776}
777
793void vpMeLine::display(const vpImage<unsigned char> &I, const vpMeSite &PExt1, const vpMeSite &PExt2,
794 const std::list<vpMeSite> &site_list, const double &A, const double &B, const double &C,
795 const vpColor &color, unsigned int thickness)
796{
797 vpMeLine::displayLine(I, PExt1, PExt2, site_list, A, B, C, color, thickness);
798}
799
815void vpMeLine::display(const vpImage<vpRGBa> &I, const vpMeSite &PExt1, const vpMeSite &PExt2,
816 const std::list<vpMeSite> &site_list, const double &A, const double &B, const double &C,
817 const vpColor &color, unsigned int thickness)
818{
819
820 vpMeLine::displayLine(I, PExt1, PExt2, site_list, A, B, C, color, thickness);
821}
822#endif // Deprecated
823
824
825void vpMeLine::displayLine(const vpImage<unsigned char> &I, const vpMeSite &PExt1, const vpMeSite &PExt2, const double &A,
826 const double &B, const double &C, const vpColor &color, unsigned int thickness)
827{
828 vpImagePoint ip1, ip2;
829
830 if (fabs(A) < fabs(B)) {
831 double i1, j1, i2, j2;
832 i1 = 0;
833 j1 = (-A * i1 - C) / B;
834 i2 = I.getHeight() - 1.0;
835 j2 = (-A * i2 - C) / B;
836
837 ip1.set_i(i1);
838 ip1.set_j(j1);
839 ip2.set_i(i2);
840 ip2.set_j(j2);
841 vpDisplay::displayLine(I, ip1, ip2, color);
842 }
843 else {
844 double i1, j1, i2, j2;
845 j1 = 0;
846 i1 = -(B * j1 + C) / A;
847 j2 = I.getWidth() - 1.0;
848 i2 = -(B * j2 + C) / A;
849
850 ip1.set_i(i1);
851 ip1.set_j(j1);
852 ip2.set_i(i2);
853 ip2.set_j(j2);
854 vpDisplay::displayLine(I, ip1, ip2, color);
855 }
856
857 project(A, B, C, PExt1, ip1);
858 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
859
860 project(A, B, C, PExt2, ip1);
861 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
862}
863
864void vpMeLine::displayLine(const vpImage<vpRGBa> &I, const vpMeSite &PExt1, const vpMeSite &PExt2, const double &A,
865 const double &B, const double &C, const vpColor &color, unsigned int thickness)
866{
867 vpImagePoint ip1, ip2;
868
869 if (fabs(A) < fabs(B)) {
870 double i1, j1, i2, j2;
871 i1 = 0;
872 j1 = (-A * i1 - C) / B;
873 i2 = I.getHeight() - 1.0;
874 j2 = (-A * i2 - C) / B;
875
876 ip1.set_i(i1);
877 ip1.set_j(j1);
878 ip2.set_i(i2);
879 ip2.set_j(j2);
880 vpDisplay::displayLine(I, ip1, ip2, color);
881 }
882 else {
883 double i1, j1, i2, j2;
884 j1 = 0;
885 i1 = -(B * j1 + C) / A;
886 j2 = I.getWidth() - 1.0;
887 i2 = -(B * j2 + C) / A;
888
889 ip1.set_i(i1);
890 ip1.set_j(j1);
891 ip2.set_i(i2);
892 ip2.set_j(j2);
893 vpDisplay::displayLine(I, ip1, ip2, color);
894 }
895 project(A, B, C, PExt1, ip1);
896 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
897
898 project(A, B, C, PExt2, ip1);
899 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
900}
901
902void vpMeLine::displayLine(const vpImage<unsigned char> &I, const vpMeSite &PExt1, const vpMeSite &PExt2,
903 const std::list<vpMeSite> &site_list, const double &A, const double &B, const double &C,
904 const vpColor &color, unsigned int thickness)
905{
906 vpImagePoint ip;
907 std::list<vpMeSite>::const_iterator end = site_list.end();
908
909 for (std::list<vpMeSite>::const_iterator it = site_list.begin(); it != end; ++it) {
910 vpMeSite pix = *it;
911 ip.set_i(pix.m_ifloat);
912 ip.set_j(pix.m_jfloat);
913
914 if (pix.getState() == vpMeSite::M_ESTIMATOR)
915 vpDisplay::displayCross(I, ip, 5, vpColor::green, thickness);
916 else
917 vpDisplay::displayCross(I, ip, 5, color, thickness);
918 }
919
920 vpImagePoint ip1, ip2;
921
922 if (fabs(A) < fabs(B)) {
923 double i1, j1, i2, j2;
924 i1 = 0;
925 j1 = (-A * i1 - C) / B;
926 i2 = I.getHeight() - 1.0;
927 j2 = (-A * i2 - C) / B;
928
929 ip1.set_i(i1);
930 ip1.set_j(j1);
931 ip2.set_i(i2);
932 ip2.set_j(j2);
933 vpDisplay::displayLine(I, ip1, ip2, color);
934 }
935 else {
936 double i1, j1, i2, j2;
937 j1 = 0;
938 i1 = -(B * j1 + C) / A;
939 j2 = I.getWidth() - 1.0;
940 i2 = -(B * j2 + C) / A;
941
942 ip1.set_i(i1);
943 ip1.set_j(j1);
944 ip2.set_i(i2);
945 ip2.set_j(j2);
946 vpDisplay::displayLine(I, ip1, ip2, color);
947 }
948 project(A, B, C, PExt1, ip1);
949 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
950
951 project(A, B, C, PExt2, ip1);
952 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
953}
954
955void vpMeLine::displayLine(const vpImage<vpRGBa> &I, const vpMeSite &PExt1, const vpMeSite &PExt2,
956 const std::list<vpMeSite> &site_list, const double &A, const double &B, const double &C,
957 const vpColor &color, unsigned int thickness)
958{
959 vpImagePoint ip;
960 std::list<vpMeSite>::const_iterator end = site_list.end();
961
962 for (std::list<vpMeSite>::const_iterator it = site_list.begin(); it != end; ++it) {
963 vpMeSite pix = *it;
964 ip.set_i(pix.m_ifloat);
965 ip.set_j(pix.m_jfloat);
966
967 if (pix.getState() == vpMeSite::M_ESTIMATOR)
968 vpDisplay::displayCross(I, ip, 5, vpColor::green, thickness);
969 else
970 vpDisplay::displayCross(I, ip, 5, color, thickness);
971 }
972
973 vpImagePoint ip1, ip2;
974
975 if (fabs(A) < fabs(B)) {
976 double i1, j1, i2, j2;
977 i1 = 0;
978 j1 = (-A * i1 - C) / B;
979 i2 = I.getHeight() - 1.0;
980 j2 = (-A * i2 - C) / B;
981
982 ip1.set_i(i1);
983 ip1.set_j(j1);
984 ip2.set_i(i2);
985 ip2.set_j(j2);
986 vpDisplay::displayLine(I, ip1, ip2, color);
987 }
988 else {
989 double i1, j1, i2, j2;
990 j1 = 0;
991 i1 = -(B * j1 + C) / A;
992 j2 = I.getWidth() - 1.0;
993 i2 = -(B * j2 + C) / A;
994
995 ip1.set_i(i1);
996 ip1.set_j(j1);
997 ip2.set_i(i2);
998 ip2.set_j(j2);
999 vpDisplay::displayLine(I, ip1, ip2, color);
1000 }
1001 project(A, B, C, PExt1, ip1);
1002 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1003
1004 project(A, B, C, PExt2, ip1);
1005 vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1006}
1007END_VISP_NAMESPACE
unsigned int getCols() const
Definition vpArray2D.h:423
Implementation of column vector and the associated operations.
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
static const vpColor red
Definition vpColor.h:198
static const vpColor blue
Definition vpColor.h:204
static const vpColor green
Definition vpColor.h:201
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void flush(const vpImage< unsigned char > &I)
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 ...
void set_j(double jj)
double get_j() const
void set_ij(double ii, double jj)
void set_i(double ii)
double get_i() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
Provides simple mathematics computation tools that are not available in the C mathematics library (ma...
Definition vpMath.h:111
static double rad(double deg)
Definition vpMath.h:129
static double sqr(double x)
Definition vpMath.h:203
static int round(double x)
Definition vpMath.h:413
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
unsigned int nullSpace(vpMatrix &kerA, double svThreshold=1e-6) const
double m_theta
theta parameter of the line
Definition vpMeLine.h:470
int m_sign
Sign.
Definition vpMeLine.h:472
unsigned int plugHoles(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:361
void updateDelta()
Definition vpMeLine.cpp:593
void display(const vpImage< unsigned char > &I, const vpColor &color, unsigned int thickness=1)
Definition vpMeLine.cpp:177
void reSample(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:561
double m_c
Parameter c of the line equation a*i + b*j + c = 0.
Definition vpMeLine.h:476
double m_delta
Angle in rad between the extremities.
Definition vpMeLine.h:471
double m_rho
rho parameter of the line
Definition vpMeLine.h:469
void track(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:607
void getExtremities(vpImagePoint &ip1, vpImagePoint &ip2) const
Definition vpMeLine.cpp:703
static void project(double a, double b, double c, const vpMeSite &P, vpImagePoint &iP)
Definition vpMeLine.cpp:66
static void displayLine(const vpImage< unsigned char > &I, const vpMeSite &PExt1, const vpMeSite &PExt2, const double &A, const double &B, const double &C, const vpColor &color=vpColor::green, unsigned int thickness=1)
Definition vpMeLine.cpp:825
double m_a
Parameter a of the line equation a*i + b*j + c = 0.
Definition vpMeLine.h:474
virtual void sample(const vpImage< unsigned char > &I, bool doNotTrack=false) VP_OVERRIDE
Definition vpMeLine.cpp:112
void leastSquare(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:207
double m_b
Parameter b of the line equation a*i + b*j + c = 0.
Definition vpMeLine.h:475
vpMeSite m_PExt[2]
Definition vpMeLine.h:466
void setExtremities()
Definition vpMeLine.cpp:355
void initTracking(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:187
static bool intersection(const vpMeLine &line1, const vpMeLine &line2, vpImagePoint &iP)
Definition vpMeLine.cpp:714
virtual ~vpMeLine() VP_OVERRIDE
Definition vpMeLine.cpp:90
virtual unsigned int seekExtremities(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:445
vpMeLine & operator=(const vpMeLine &meline)
Definition vpMeLine.cpp:95
void computeRhoTheta()
Definition vpMeLine.cpp:653
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'....
Definition vpMeSite.h:75
int m_mask_sign
Mask sign.
Definition vpMeSite.h:114
@ M_ESTIMATOR
Point detected as an outlier during virtual visual-servoing.
Definition vpMeSite.h:99
@ NO_SUPPRESSION
Point successfully tracked.
Definition vpMeSite.h:93
void setDisplay(vpMeSiteDisplayType select)
Definition vpMeSite.h:287
double m_ifloat
Subpixel coordinates along i of a site.
Definition vpMeSite.h:110
double convolution(const vpImage< unsigned char > &ima, const vpMe *me)
Definition vpMeSite.cpp:259
void setAlpha(const double &a)
Definition vpMeSite.h:282
void init()
Definition vpMeSite.cpp:70
unsigned int getIndex() const
Definition vpMeSite.h:224
vpMeSiteState getState() const
Definition vpMeSite.h:306
int m_j
Integer coordinates along j of a site.
Definition vpMeSite.h:108
int m_i
Integer coordinate along i of a site.
Definition vpMeSite.h:106
double m_jfloat
Subpixel coordinates along j of a site.
Definition vpMeSite.h:112
void setContrastThreshold(const double &thresh, const vpMe &me)
Definition vpMeSite.h:326
void track(const vpImage< unsigned char > &I, const vpMe *me, const bool &test_contrast=true)
Definition vpMeSite.cpp:330
void setState(const vpMeSiteState &flag)
Definition vpMeSite.h:296
void initTracking(const vpImage< unsigned char > &I)
const vpImage< bool > * m_mask
Mask used to disable tracking on a part of image.
unsigned int numberOfSignal()
vpMeSite::vpMeSiteDisplayType m_selectDisplay
Moving-edges display type.
void track(const vpImage< unsigned char > &I)
vpMe * m_me
Moving edges initialisation parameters.
static bool inRoiMask(const vpImage< bool > *mask, unsigned int i, unsigned int j)
void display(const vpImage< unsigned char > &I)
bool outOfImage(int i, int j, int border, int nrows, int ncols)
const vpImage< bool > * m_maskCandidates
Mask used to determine candidate points for initialization in an image.
std::list< vpMeSite > m_meList
static bool inMeMaskCandidates(const vpImage< bool > *meMaskCandidates, unsigned int i, unsigned int j)
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.
@ notEnoughPointError
Not enough point to track.
@ initializationError
Tracker initialization error.
@ fatalError
Tracker fatal error.
#define vpCDEBUG(level)
Definition vpDebug.h:554
#define vpDERROR_TRACE
Definition vpDebug.h:499
#define vpERROR_TRACE
Definition vpDebug.h:423
#define vpDEBUG_ENABLE(level)
Definition vpDebug.h:585