Visual Servoing Platform  version 3.1.0
vpMeLine.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 
44 #include <algorithm> // (std::min)
45 #include <cmath> // std::fabs
46 #include <limits> // numeric_limits
47 #include <stdlib.h>
48 #include <visp3/core/vpImagePoint.h>
49 #include <visp3/core/vpMath.h>
50 #include <visp3/core/vpRobust.h>
51 #include <visp3/core/vpTrackingException.h>
52 #include <visp3/me/vpMe.h>
53 #include <visp3/me/vpMeLine.h>
54 #include <visp3/me/vpMeSite.h>
55 #include <visp3/me/vpMeTracker.h>
56 
57 #define INCR_MIN 1
58 
59 void computeDelta(double &delta, int i1, int j1, int i2, int j2);
60 
61 static void normalizeAngle(double &delta)
62 {
63  while (delta > M_PI) {
64  delta -= M_PI;
65  }
66  while (delta < -M_PI) {
67  delta += M_PI;
68  }
69 }
70 
71 void computeDelta(double &delta, int i1, int j1, int i2, int j2)
72 {
73 
74  double B = double(i1 - i2);
75  double A = double(j1 - j2);
76 
77  delta = atan2(B, A);
78  delta -= M_PI / 2.0;
79  normalizeAngle(delta);
80 }
81 
82 static void project(double a, double b, double c, double i, double j, double &ip, double &jp)
83 {
84  if (fabs(a) > fabs(b)) {
85  jp = (vpMath::sqr(a) * j - a * b * i - c * b) / (vpMath::sqr(a) + vpMath::sqr(b));
86  ip = (-c - b * jp) / a;
87  } else {
88  ip = (vpMath::sqr(b) * i - a * b * j - c * a) / (vpMath::sqr(a) + vpMath::sqr(b));
89  jp = (-c - a * ip) / b;
90  }
91 }
92 
99  : rho(0.), theta(0.), delta(0.), delta_1(0.), angle(0.), angle_1(90), sign(1), _useIntensityForRho(true), a(0.),
100  b(0.), c(0.)
101 {
102 }
109  : vpMeTracker(meline), rho(0.), theta(0.), delta(0.), delta_1(0.), angle(0.), angle_1(90), sign(1),
110  _useIntensityForRho(true), a(0.), b(0.), c(0.)
111 
112 {
113  rho = meline.rho;
114  theta = meline.theta;
115  delta = meline.delta;
116  delta_1 = meline.delta_1;
117  angle = meline.angle;
118  angle_1 = meline.angle_1;
119  sign = meline.sign;
120 
121  a = meline.a;
122  b = meline.b;
123  c = meline.c;
125  PExt[0] = meline.PExt[0];
126  PExt[1] = meline.PExt[1];
127 }
128 
134 vpMeLine::~vpMeLine() { list.clear(); }
135 
148 {
149  if (!me) {
150  vpDERROR_TRACE(2, "Tracking error: Moving edges not initialized");
151  throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
152  }
153 
154  int rows = (int)I.getHeight();
155  int cols = (int)I.getWidth();
156  double n_sample;
157 
158  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon()) {
159  vpERROR_TRACE("function called with sample step = 0");
160  throw(vpTrackingException(vpTrackingException::fatalError, "sample step = 0"));
161  }
162 
163  // i, j portions of the line_p
164  double diffsi = PExt[0].ifloat - PExt[1].ifloat;
165  double diffsj = PExt[0].jfloat - PExt[1].jfloat;
166 
167  double length_p = sqrt((vpMath::sqr(diffsi) + vpMath::sqr(diffsj)));
168  if (std::fabs(length_p) <= std::numeric_limits<double>::epsilon())
169  throw(vpTrackingException(vpTrackingException::fatalError, "points too close of each other to define a line"));
170  // number of samples along line_p
171  n_sample = length_p / (double)me->getSampleStep();
172 
173  double stepi = diffsi / (double)n_sample;
174  double stepj = diffsj / (double)n_sample;
175 
176  // Choose starting point
177  double is = PExt[1].ifloat;
178  double js = PExt[1].jfloat;
179 
180  // Delete old list
181  list.clear();
182 
183  // sample positions at i*me->getSampleStep() interval along the
184  // line_p, starting at PSiteExt[0]
185 
186  vpImagePoint ip;
187  for (int i = 0; i <= vpMath::round(n_sample); i++) {
188  // If point is in the image, add to the sample list
189  if (!outOfImage(vpMath::round(is), vpMath::round(js), 0, rows, cols)) {
190  vpMeSite pix; //= list.value();
191  pix.init((int)is, (int)js, delta, 0, sign);
193 
194  if (vpDEBUG_ENABLE(3)) {
195  ip.set_i(is);
196  ip.set_j(js);
198  }
199 
200  list.push_back(pix);
201  }
202  is += stepi;
203  js += stepj;
204  }
205 
206  vpCDEBUG(1) << "end vpMeLine::sample() : ";
207  vpCDEBUG(1) << n_sample << " point inserted in the list " << std::endl;
208 }
209 
223 {
224  vpMeLine::display(I, PExt[0], PExt[1], list, a, b, c, col);
225 }
226 
235 {
236  vpImagePoint ip1, ip2;
237 
238  std::cout << "Click on the line first point..." << std::endl;
239  while (vpDisplay::getClick(I, ip1) != true)
240  ;
242  vpDisplay::flush(I);
243  std::cout << "Click on the line second point..." << std::endl;
244  while (vpDisplay::getClick(I, ip2) != true)
245  ;
247  vpDisplay::flush(I);
248 
249  try {
250  initTracking(I, ip1, ip2);
251  } catch (...) {
252  vpERROR_TRACE("Error caught");
253  throw;
254  }
255 }
256 
264 {
265  vpMatrix A(numberOfSignal(), 2);
266  vpColVector x(2), x_1(2);
267  x_1 = 0;
268 
269  unsigned int i;
270 
272  r.setThreshold(2);
273  r.setIteration(0);
275  D.eye();
276  vpMatrix DA, DAmemory;
277  vpColVector DAx;
280  w = 1;
281  vpMeSite p_me;
282  unsigned int iter = 0;
283  unsigned int nos_1 = 0;
284  double distance = 100;
285 
286  if (list.size() <= 2 || numberOfSignal() <= 2) {
287  // vpERROR_TRACE("Not enough point") ;
288  vpCDEBUG(1) << "Not enough point";
290  }
291 
292  if ((fabs(b) >= 0.9)) // Construction du systeme Ax=B
293  // a i + j + c = 0
294  // A = (i 1) B = (-j)
295  {
296  nos_1 = numberOfSignal();
297  unsigned int k = 0;
298  for (std::list<vpMeSite>::const_iterator it = list.begin(); it != list.end(); ++it) {
299  p_me = *it;
300  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
301  A[k][0] = p_me.ifloat;
302  A[k][1] = 1;
303  B[k] = -p_me.jfloat;
304  k++;
305  }
306  }
307 
308  while (iter < 4 && distance > 0.05) {
309  DA = D * A;
310  x = DA.pseudoInverse(1e-26) * D * B;
311 
312  vpColVector residu(nos_1);
313  residu = B - A * x;
314  r.setIteration(iter);
315  r.MEstimator(vpRobust::TUKEY, residu, w);
316 
317  k = 0;
318  for (i = 0; i < nos_1; i++) {
319  D[k][k] = w[k];
320  k++;
321  }
322  iter++;
323  distance = fabs(x[0] - x_1[0]) + fabs(x[1] - x_1[1]);
324  x_1 = x;
325  }
326 
327  k = 0;
328  for (std::list<vpMeSite>::iterator it = list.begin(); it != list.end(); ++it) {
329  p_me = *it;
330  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
331  if (w[k] < 0.2) {
333 
334  *it = p_me;
335  }
336  k++;
337  }
338  }
339 
340  // mise a jour de l'equation de la droite
341  a = x[0];
342  b = 1;
343  c = x[1];
344 
345  double s = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
346  a /= s;
347  b /= s;
348  c /= s;
349  }
350 
351  else // Construction du systeme Ax=B
352  // i + bj + c = 0
353  // A = (j 1) B = (-i)
354  {
355  nos_1 = numberOfSignal();
356  unsigned int k = 0;
357  for (std::list<vpMeSite>::const_iterator it = list.begin(); it != list.end(); ++it) {
358  p_me = *it;
359  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
360  A[k][0] = p_me.jfloat;
361  A[k][1] = 1;
362  B[k] = -p_me.ifloat;
363  k++;
364  }
365  }
366 
367  while (iter < 4 && distance > 0.05) {
368  DA = D * A;
369  x = DA.pseudoInverse(1e-26) * D * B;
370 
371  vpColVector residu(nos_1);
372  residu = B - A * x;
373  r.setIteration(iter);
374  r.MEstimator(vpRobust::TUKEY, residu, w);
375 
376  k = 0;
377  for (i = 0; i < nos_1; i++) {
378  D[k][k] = w[k];
379  k++;
380  }
381  iter++;
382  distance = fabs(x[0] - x_1[0]) + fabs(x[1] - x_1[1]);
383  x_1 = x;
384  }
385 
386  k = 0;
387  for (std::list<vpMeSite>::iterator it = list.begin(); it != list.end(); ++it) {
388  p_me = *it;
389  if (p_me.getState() == vpMeSite::NO_SUPPRESSION) {
390  if (w[k] < 0.2) {
392 
393  *it = p_me;
394  }
395  k++;
396  }
397  }
398  a = 1;
399  b = x[0];
400  c = x[1];
401 
402  double s = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
403  a /= s;
404  b /= s;
405  c /= s;
406  }
407 
408  // mise a jour du delta
409  delta = atan2(a, b);
410 
411  normalizeAngle(delta);
412 }
413 
424 {
425  vpCDEBUG(1) << " begin vpMeLine::initTracking()" << std::endl;
426 
427  int i1s, j1s, i2s, j2s;
428 
429  i1s = vpMath::round(ip1.get_i());
430  i2s = vpMath::round(ip2.get_i());
431  j1s = vpMath::round(ip1.get_j());
432  j2s = vpMath::round(ip2.get_j());
433 
434  try {
435 
436  // 1. On fait ce qui concerne les droites (peut etre vide)
437  {
438  // Points extremites
439  PExt[0].ifloat = (float)ip1.get_i();
440  PExt[0].jfloat = (float)ip1.get_j();
441  PExt[1].ifloat = (float)ip2.get_i();
442  PExt[1].jfloat = (float)ip2.get_j();
443 
444  double angle_ = atan2((double)(i1s - i2s), (double)(j1s - j2s));
445  a = cos(angle_);
446  b = sin(angle_);
447 
448  // Real values of a, b can have an other sign. So to get the good values
449  // of a and b in order to initialise then c, we call track(I) just below
450 
451  computeDelta(delta, i1s, j1s, i2s, j2s);
452  delta_1 = delta;
453 
454  // vpTRACE("a: %f b: %f c: %f -b/a: %f delta: %f", a, b, c, -(b/a),
455  // delta);
456 
457  sample(I);
458  }
459  // 2. On appelle ce qui n'est pas specifique
460  {
462  }
463  // Call track(I) to give the good sign to a and b and to initialise c
464  // which can be used for the display
465  track(I);
466  } catch (...) {
467  vpERROR_TRACE("Error caught");
468  throw;
469  }
470  vpCDEBUG(1) << " end vpMeLine::initTracking()" << std::endl;
471 }
472 
477 {
478  // Loop through list of sites to track
479  for (std::list<vpMeSite>::iterator it = list.begin(); it != list.end();) {
480  vpMeSite s = *it; // current reference pixel
481 
483  it = list.erase(it);
484  else
485  ++it;
486  }
487 }
488 
493 {
494  double imin = +1e6;
495  double jmin = +1e6;
496  double imax = -1;
497  double jmax = -1;
498 
499  // Loop through list of sites to track
500  for (std::list<vpMeSite>::const_iterator it = list.begin(); it != list.end(); ++it) {
501  vpMeSite s = *it; // current reference pixel
502  if (s.ifloat < imin) {
503  imin = s.ifloat;
504  jmin = s.jfloat;
505  }
506 
507  if (s.ifloat > imax) {
508  imax = s.ifloat;
509  jmax = s.jfloat;
510  }
511  }
512 
513  PExt[0].ifloat = imin;
514  PExt[0].jfloat = jmin;
515  PExt[1].ifloat = imax;
516  PExt[1].jfloat = jmax;
517 
518  if (fabs(imin - imax) < 25) {
519  for (std::list<vpMeSite>::const_iterator it = list.begin(); it != list.end(); ++it) {
520  vpMeSite s = *it; // current reference pixel
521  if (s.jfloat < jmin) {
522  imin = s.ifloat;
523  jmin = s.jfloat;
524  }
525 
526  if (s.jfloat > jmax) {
527  imax = s.ifloat;
528  jmax = s.jfloat;
529  }
530  }
531  PExt[0].ifloat = imin;
532  PExt[0].jfloat = jmin;
533  PExt[1].ifloat = imax;
534  PExt[1].jfloat = jmax;
535  }
536 }
537 
550 {
551  vpCDEBUG(1) << "begin vpMeLine::sample() : " << std::endl;
552 
553  if (!me) {
554  vpDERROR_TRACE(2, "Tracking error: Moving edges not initialized");
555  throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
556  }
557 
558  int rows = (int)I.getHeight();
559  int cols = (int)I.getWidth();
560  double n_sample;
561 
562  // if (me->getSampleStep()==0)
563  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon()) {
564 
565  vpERROR_TRACE("function called with sample step = 0");
566  throw(vpTrackingException(vpTrackingException::fatalError, "sample step = 0"));
567  }
568 
569  // i, j portions of the line_p
570  double diffsi = PExt[0].ifloat - PExt[1].ifloat;
571  double diffsj = PExt[0].jfloat - PExt[1].jfloat;
572 
573  double s = vpMath::sqr(diffsi) + vpMath::sqr(diffsj);
574 
575  double di = diffsi / sqrt(s); // pas de risque de /0 car d(P1,P2) >0
576  double dj = diffsj / sqrt(s);
577 
578  double length_p = sqrt((vpMath::sqr(diffsi) + vpMath::sqr(diffsj)));
579 
580  // number of samples along line_p
581  n_sample = length_p / (double)me->getSampleStep();
582  double sample_step = (double)me->getSampleStep();
583 
584  vpMeSite P;
585  P.init((int)PExt[0].ifloat, (int)PExt[0].jfloat, delta_1, 0, sign);
587 
588  unsigned int memory_range = me->getRange();
589  me->setRange(1);
590 
591  vpImagePoint ip;
592 
593  for (int i = 0; i < 3; i++) {
594  P.ifloat = P.ifloat + di * sample_step;
595  P.i = (int)P.ifloat;
596  P.jfloat = P.jfloat + dj * sample_step;
597  P.j = (int)P.jfloat;
598 
599  if (!outOfImage(P.i, P.j, 5, rows, cols)) {
600  P.track(I, me, false);
601 
602  if (P.getState() == vpMeSite::NO_SUPPRESSION) {
603  list.push_back(P);
604  if (vpDEBUG_ENABLE(3)) {
605  ip.set_i(P.i);
606  ip.set_j(P.j);
607 
609  }
610  } else {
611  if (vpDEBUG_ENABLE(3)) {
612  ip.set_i(P.i);
613  ip.set_j(P.j);
615  }
616  }
617  }
618  }
619 
620  P.init((int)PExt[1].ifloat, (int)PExt[1].jfloat, delta_1, 0, sign);
622  for (int i = 0; i < 3; i++) {
623  P.ifloat = P.ifloat - di * sample_step;
624  P.i = (int)P.ifloat;
625  P.jfloat = P.jfloat - dj * sample_step;
626  P.j = (int)P.jfloat;
627 
628  if (!outOfImage(P.i, P.j, 5, rows, cols)) {
629  P.track(I, me, false);
630 
631  if (P.getState() == vpMeSite::NO_SUPPRESSION) {
632  list.push_back(P);
633  if (vpDEBUG_ENABLE(3)) {
634  ip.set_i(P.i);
635  ip.set_j(P.j);
637  }
638  } else {
639  if (vpDEBUG_ENABLE(3)) {
640  ip.set_i(P.i);
641  ip.set_j(P.j);
643  }
644  }
645  }
646  }
647 
648  me->setRange(memory_range);
649 
650  vpCDEBUG(1) << "end vpMeLine::sample() : ";
651  vpCDEBUG(1) << n_sample << " point inserted in the list " << std::endl;
652 }
653 
666 {
667  double i1, j1, i2, j2;
668 
669  if (!me) {
670  vpDERROR_TRACE(2, "Tracking error: Moving edges not initialized");
671  throw(vpTrackingException(vpTrackingException::initializationError, "Moving edges not initialized"));
672  }
673 
674  project(a, b, c, PExt[0].ifloat, PExt[0].jfloat, i1, j1);
675  project(a, b, c, PExt[1].ifloat, PExt[1].jfloat, i2, j2);
676 
677  // Points extremites
678  PExt[0].ifloat = i1;
679  PExt[0].jfloat = j1;
680  PExt[1].ifloat = i2;
681  PExt[1].jfloat = j2;
682 
683  double d = sqrt(vpMath::sqr(i1 - i2) + vpMath::sqr(j1 - j2));
684 
685  unsigned int n = numberOfSignal();
686  double expecteddensity = d / (double)me->getSampleStep();
687 
688  if ((double)n < 0.9 * expecteddensity) {
689  double delta_new = delta;
690  delta = delta_1;
691  sample(I);
692  delta = delta_new;
693  // 2. On appelle ce qui n'est pas specifique
694  {
696  }
697  }
698 }
699 
705 {
706  vpMeSite p_me;
707 
708  double angle_ = delta + M_PI / 2;
709  double diff = 0;
710 
711  while (angle_ < 0)
712  angle_ += M_PI;
713  while (angle_ > M_PI)
714  angle_ -= M_PI;
715 
716  angle_ = vpMath::round(angle_ * 180 / M_PI);
717 
718  // if(fabs(angle_) == 180 )
719  if (std::fabs(std::fabs(angle_) - 180) <= std::numeric_limits<double>::epsilon()) {
720  angle_ = 0;
721  }
722 
723  // std::cout << "angle theta : " << theta << std::endl ;
724  diff = fabs(angle_ - angle_1);
725  if (diff > 90)
726  sign *= -1;
727 
728  angle_1 = angle_;
729 
730  for (std::list<vpMeSite>::iterator it = list.begin(); it != list.end(); ++it) {
731  p_me = *it;
732  p_me.alpha = delta;
733  p_me.mask_sign = sign;
734  *it = p_me;
735  }
736  delta_1 = delta;
737 }
738 
746 {
747  vpCDEBUG(1) << "begin vpMeLine::track()" << std::endl;
748 
749  // 1. On fait ce qui concerne les droites (peut etre vide)
750  {} // 2. On appelle ce qui n'est pas specifique
751  {
753  }
754 
755  // 3. On revient aux droites
756  {
757  // supression des points rejetes par les ME
758  suppressPoints();
759  setExtremities();
760 
761  // Estimation des parametres de la droite aux moindres carre
762  try {
763  leastSquare();
764  } catch (...) {
765  vpERROR_TRACE("Error caught");
766  throw;
767  }
768 
769  // recherche de point aux extremite de la droites
770  // dans le cas d'un glissement
771  seekExtremities(I);
772 
773  setExtremities();
774  try {
775  leastSquare();
776  } catch (...) {
777  vpERROR_TRACE("Error caught");
778  throw;
779  }
780 
781  // suppression des points rejetes par la regression robuste
782  suppressPoints();
783  setExtremities();
784 
785  // reechantillonage si necessaire
786  reSample(I);
787 
788  // remet a jour l'angle delta pour chaque point de la liste
789 
790  updateDelta();
791 
792  // Remise a jour de delta dans la liste de site me
793  if (vpDEBUG_ENABLE(2)) {
794  display(I, vpColor::red);
796  vpDisplay::flush(I);
797  }
798  }
799 
800  computeRhoTheta(I);
801 
802  vpCDEBUG(1) << "end vpMeLine::track()" << std::endl;
803 }
804 
805 void vpMeLine::update_indices(double theta, int i, int j, int incr, int &i1, int &i2, int &j1, int &j2)
806 {
807  i1 = (int)(i + cos(theta) * incr);
808  j1 = (int)(j + sin(theta) * incr);
809 
810  i2 = (int)(i - cos(theta) * incr);
811  j2 = (int)(j - sin(theta) * incr);
812 }
813 
821 {
822  // rho = -c ;
823  // theta = atan2(a,b) ;
824  rho = fabs(c);
825  theta = atan2(b, a);
826 
827  while (theta >= M_PI)
828  theta -= M_PI;
829  while (theta < 0)
830  theta += M_PI;
831 
832  if (_useIntensityForRho) {
833 
834  /* while(theta < -M_PI) theta += 2*M_PI ;
835  while(theta >= M_PI) theta -= 2*M_PI ;
836 
837  // If theta is between -90 and -180 get the equivalent
838  // between 0 and 90
839  if(theta <-M_PI/2)
840  {
841  theta += M_PI ;
842  rho *= -1 ;
843  }
844  // If theta is between 90 and 180 get the equivalent
845  // between 0 and -90
846  if(theta >M_PI/2)
847  {
848  theta -= M_PI ;
849  rho *= -1 ;
850  }
851  */
852  // convention pour choisir le signe de rho
853  int i, j;
854  i = vpMath::round((PExt[0].ifloat + PExt[1].ifloat) / 2);
855  j = vpMath::round((PExt[0].jfloat + PExt[1].jfloat) / 2);
856 
857  int end = false;
858  int incr = 10;
859 
860  int i1 = 0, i2 = 0, j1 = 0, j2 = 0;
861  unsigned char v1 = 0, v2 = 0;
862 
863  int width_ = (int)I.getWidth();
864  int height_ = (int)I.getHeight();
865  update_indices(theta, i, j, incr, i1, i2, j1, j2);
866 
867  if (i1 < 0 || i1 >= height_ || i2 < 0 || i2 >= height_ || j1 < 0 || j1 >= width_ || j2 < 0 || j2 >= width_) {
868  double rho_lim1 = fabs((double)i / cos(theta));
869  double rho_lim2 = fabs((double)j / sin(theta));
870 
871  double co_rho_lim1 = fabs(((double)(height_ - i)) / cos(theta));
872  double co_rho_lim2 = fabs(((double)(width_ - j)) / sin(theta));
873 
874  double rho_lim = (std::min)(rho_lim1, rho_lim2);
875  double co_rho_lim = (std::min)(co_rho_lim1, co_rho_lim2);
876  incr = (int)std::floor((std::min)(rho_lim, co_rho_lim));
877  if (incr < INCR_MIN) {
878  vpERROR_TRACE("increment is too small");
879  throw(vpTrackingException(vpTrackingException::fatalError, "increment is too small"));
880  }
881  update_indices(theta, i, j, incr, i1, i2, j1, j2);
882  }
883 
884  while (!end) {
885  end = true;
886  unsigned int i1_ = static_cast<unsigned int>(i1);
887  unsigned int j1_ = static_cast<unsigned int>(j1);
888  unsigned int i2_ = static_cast<unsigned int>(i2);
889  unsigned int j2_ = static_cast<unsigned int>(j2);
890  v1 = I[i1_][j1_];
891  v2 = I[i2_][j2_];
892  if (abs(v1 - v2) < 1) {
893  incr--;
894  end = false;
895  if (incr == 1) {
896  throw(vpException(vpException::fatalError, "In vpMeLine cannot determine rho sign, since "
897  "there is no gray level difference between both "
898  "sides of the line"));
899  }
900  }
901  update_indices(theta, i, j, incr, i1, i2, j1, j2);
902  }
903 
904  if (theta >= 0 && theta <= M_PI / 2) {
905  if (v2 < v1) {
906  theta += M_PI;
907  rho *= -1;
908  }
909  }
910 
911  else {
912  double jinter;
913  jinter = -c / b;
914  if (v2 < v1) {
915  theta += M_PI;
916  if (jinter > 0) {
917  rho *= -1;
918  }
919  }
920 
921  else {
922  if (jinter < 0) {
923  rho *= -1;
924  }
925  }
926  }
927 
928  if (vpDEBUG_ENABLE(2)) {
929  vpImagePoint ip, ip1, ip2;
930 
931  ip.set_i(i);
932  ip.set_j(j);
933  ip1.set_i(i1);
934  ip1.set_j(j1);
935  ip2.set_i(i2);
936  ip2.set_j(j2);
937 
940  }
941  }
942 }
943 
954 double vpMeLine::getRho() const { return rho; }
955 
959 double vpMeLine::getTheta() const { return theta; }
960 
969 {
970  /*Return the coordinates of the extremities of the line*/
971  ip1.set_i(PExt[0].ifloat);
972  ip1.set_j(PExt[0].jfloat);
973  ip2.set_i(PExt[1].ifloat);
974  ip2.set_j(PExt[1].jfloat);
975 }
976 
989 bool vpMeLine::intersection(const vpMeLine &line1, const vpMeLine &line2, vpImagePoint &ip)
990 {
991  double a1 = line1.a;
992  double b1 = line1.b;
993  double c1 = line1.c;
994  double a2 = line2.a;
995  double b2 = line2.b;
996  double c2 = line2.c;
997 
998  try {
999  double i = 0, j = 0;
1000  double denom = 0;
1001 
1002  if (a1 > 0.1) {
1003  denom = (-(a2 / a1) * b1 + b2);
1004 
1005  // if (denom == 0)
1006  if (std::fabs(denom) <= std::numeric_limits<double>::epsilon()) {
1007  std::cout << "!!!!!!!!!!!!! Problem : Lines are parallel !!!!!!!!!!!!!" << std::endl;
1008  return (false);
1009  }
1010 
1011  // if (denom != 0 )
1012  if (std::fabs(denom) > std::numeric_limits<double>::epsilon()) {
1013  j = ((a2 / a1) * c1 - c2) / denom;
1014  i = (-b1 * j - c1) / a1;
1015  }
1016  }
1017 
1018  else {
1019  denom = (-(b2 / b1) * a1 + a2);
1020 
1021  // if (denom == 0)
1022  if (std::fabs(denom) <= std::numeric_limits<double>::epsilon()) {
1023  std::cout << "!!!!!!!!!!!!! Problem : Lines are parallel !!!!!!!!!!!!!" << std::endl;
1024  return (false);
1025  }
1026 
1027  // if (denom != 0 )
1028  if (std::fabs(denom) > std::numeric_limits<double>::epsilon()) {
1029  i = ((b2 / b1) * c1 - c2) / denom;
1030  j = (-a1 * i - c1) / b1;
1031  }
1032  }
1033  ip.set_i(i);
1034  ip.set_j(j);
1035 
1036  return (true);
1037  } catch (...) {
1038  return (false);
1039  }
1040 }
1041 
1062 void vpMeLine::display(const vpImage<unsigned char> &I, const vpMeSite &PExt1, const vpMeSite &PExt2, const double &A,
1063  const double &B, const double &C, const vpColor &color, unsigned int thickness)
1064 {
1065  vpImagePoint ip1, ip2;
1066 
1067  if (fabs(A) < fabs(B)) {
1068  double i1, j1, i2, j2;
1069  i1 = 0;
1070  j1 = (-A * i1 - C) / B;
1071  i2 = I.getHeight() - 1.0;
1072  j2 = (-A * i2 - C) / B;
1073 
1074  ip1.set_i(i1);
1075  ip1.set_j(j1);
1076  ip2.set_i(i2);
1077  ip2.set_j(j2);
1078  vpDisplay::displayLine(I, ip1, ip2, color);
1079  // vpDisplay::flush(I);
1080 
1081  } else {
1082  double i1, j1, i2, j2;
1083  j1 = 0;
1084  i1 = -(B * j1 + C) / A;
1085  j2 = I.getWidth() - 1.0;
1086  i2 = -(B * j2 + C) / A;
1087 
1088  ip1.set_i(i1);
1089  ip1.set_j(j1);
1090  ip2.set_i(i2);
1091  ip2.set_j(j2);
1092  vpDisplay::displayLine(I, ip1, ip2, color);
1093  // vpDisplay::flush(I);
1094  }
1095 
1096  ip1.set_i(PExt1.ifloat);
1097  ip1.set_j(PExt1.jfloat);
1098  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1099 
1100  ip1.set_i(PExt2.ifloat);
1101  ip1.set_j(PExt2.jfloat);
1102  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1103 }
1104 
1125 void vpMeLine::display(const vpImage<vpRGBa> &I, const vpMeSite &PExt1, const vpMeSite &PExt2, const double &A,
1126  const double &B, const double &C, const vpColor &color, unsigned int thickness)
1127 {
1128  vpImagePoint ip1, ip2;
1129 
1130  if (fabs(A) < fabs(B)) {
1131  double i1, j1, i2, j2;
1132  i1 = 0;
1133  j1 = (-A * i1 - C) / B;
1134  i2 = I.getHeight() - 1.0;
1135  j2 = (-A * i2 - C) / B;
1136 
1137  ip1.set_i(i1);
1138  ip1.set_j(j1);
1139  ip2.set_i(i2);
1140  ip2.set_j(j2);
1141  vpDisplay::displayLine(I, ip1, ip2, color);
1142  // vpDisplay::flush(I);
1143 
1144  } else {
1145  double i1, j1, i2, j2;
1146  j1 = 0;
1147  i1 = -(B * j1 + C) / A;
1148  j2 = I.getWidth() - 1.0;
1149  i2 = -(B * j2 + C) / A;
1150 
1151  ip1.set_i(i1);
1152  ip1.set_j(j1);
1153  ip2.set_i(i2);
1154  ip2.set_j(j2);
1155  vpDisplay::displayLine(I, ip1, ip2, color);
1156  // vpDisplay::flush(I);
1157  }
1158 
1159  ip1.set_i(PExt1.ifloat);
1160  ip1.set_j(PExt1.jfloat);
1161  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1162 
1163  ip1.set_i(PExt2.ifloat);
1164  ip1.set_j(PExt2.jfloat);
1165  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1166 }
1167 
1190 void vpMeLine::display(const vpImage<unsigned char> &I, const vpMeSite &PExt1, const vpMeSite &PExt2,
1191  const std::list<vpMeSite> &site_list, const double &A, const double &B, const double &C,
1192  const vpColor &color, unsigned int thickness)
1193 {
1194  vpImagePoint ip;
1195 
1196  for (std::list<vpMeSite>::const_iterator it = site_list.begin(); it != site_list.end(); ++it) {
1197  vpMeSite pix = *it;
1198  ip.set_i(pix.ifloat);
1199  ip.set_j(pix.jfloat);
1200 
1201  if (pix.getState() == vpMeSite::M_ESTIMATOR)
1202  vpDisplay::displayCross(I, ip, 5, vpColor::green, thickness);
1203  else
1204  vpDisplay::displayCross(I, ip, 5, color, thickness);
1205 
1206  // vpDisplay::flush(I);
1207  }
1208 
1209  vpImagePoint ip1, ip2;
1210 
1211  if (fabs(A) < fabs(B)) {
1212  double i1, j1, i2, j2;
1213  i1 = 0;
1214  j1 = (-A * i1 - C) / B;
1215  i2 = I.getHeight() - 1.0;
1216  j2 = (-A * i2 - C) / B;
1217 
1218  ip1.set_i(i1);
1219  ip1.set_j(j1);
1220  ip2.set_i(i2);
1221  ip2.set_j(j2);
1222  vpDisplay::displayLine(I, ip1, ip2, color);
1223  // vpDisplay::flush(I);
1224 
1225  } else {
1226  double i1, j1, i2, j2;
1227  j1 = 0;
1228  i1 = -(B * j1 + C) / A;
1229  j2 = I.getWidth() - 1.0;
1230  i2 = -(B * j2 + C) / A;
1231 
1232  ip1.set_i(i1);
1233  ip1.set_j(j1);
1234  ip2.set_i(i2);
1235  ip2.set_j(j2);
1236  vpDisplay::displayLine(I, ip1, ip2, color);
1237  // vpDisplay::flush(I);
1238  }
1239 
1240  ip1.set_i(PExt1.ifloat);
1241  ip1.set_j(PExt1.jfloat);
1242  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1243 
1244  ip1.set_i(PExt2.ifloat);
1245  ip1.set_j(PExt2.jfloat);
1246  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1247 }
1248 
1271 void vpMeLine::display(const vpImage<vpRGBa> &I, const vpMeSite &PExt1, const vpMeSite &PExt2,
1272  const std::list<vpMeSite> &site_list, const double &A, const double &B, const double &C,
1273  const vpColor &color, unsigned int thickness)
1274 {
1275  vpImagePoint ip;
1276 
1277  for (std::list<vpMeSite>::const_iterator it = site_list.begin(); it != site_list.end(); ++it) {
1278  vpMeSite pix = *it;
1279  ip.set_i(pix.ifloat);
1280  ip.set_j(pix.jfloat);
1281 
1282  if (pix.getState() == vpMeSite::M_ESTIMATOR)
1283  vpDisplay::displayCross(I, ip, 5, vpColor::green, thickness);
1284  else
1285  vpDisplay::displayCross(I, ip, 5, color, thickness);
1286 
1287  // vpDisplay::flush(I);
1288  }
1289 
1290  vpImagePoint ip1, ip2;
1291 
1292  if (fabs(A) < fabs(B)) {
1293  double i1, j1, i2, j2;
1294  i1 = 0;
1295  j1 = (-A * i1 - C) / B;
1296  i2 = I.getHeight() - 1.0;
1297  j2 = (-A * i2 - C) / B;
1298 
1299  ip1.set_i(i1);
1300  ip1.set_j(j1);
1301  ip2.set_i(i2);
1302  ip2.set_j(j2);
1303  vpDisplay::displayLine(I, ip1, ip2, color);
1304  // vpDisplay::flush(I);
1305 
1306  } else {
1307  double i1, j1, i2, j2;
1308  j1 = 0;
1309  i1 = -(B * j1 + C) / A;
1310  j2 = I.getWidth() - 1.0;
1311  i2 = -(B * j2 + C) / A;
1312 
1313  ip1.set_i(i1);
1314  ip1.set_j(j1);
1315  ip2.set_i(i2);
1316  ip2.set_j(j2);
1317  vpDisplay::displayLine(I, ip1, ip2, color);
1318  // vpDisplay::flush(I);
1319  }
1320 
1321  ip1.set_i(PExt1.ifloat);
1322  ip1.set_j(PExt1.jfloat);
1323  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1324 
1325  ip1.set_i(PExt2.ifloat);
1326  ip1.set_j(PExt2.jfloat);
1327  vpDisplay::displayCross(I, ip1, 10, vpColor::green, thickness);
1328 }
vpMeLine()
Definition: vpMeLine.cpp:98
void reSample(const vpImage< unsigned char > &I)
Definition: vpMeLine.cpp:665
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:104
vpMatrix pseudoInverse(double svThreshold=1e-6) const
Definition: vpMatrix.cpp:1931
double c
Parameter c of the line equation a*i + b*j + c = 0.
Definition: vpMeLine.h:176
double get_i() const
Definition: vpImagePoint.h:204
vpMeSiteState getState() const
Definition: vpMeSite.h:188
double getTheta() const
Definition: vpMeLine.cpp:959
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
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()
double angle
Definition: vpMeLine.h:161
void setExtremities()
Definition: vpMeLine.cpp:492
Performs search in a given direction(normal) for a given distance(pixels) for a given &#39;site&#39;...
Definition: vpMeSite.h:71
#define vpERROR_TRACE
Definition: vpDebug.h:393
Class to define colors available for display functionnalities.
Definition: vpColor.h:120
double getRho() const
Definition: vpMeLine.cpp:954
double delta
Definition: vpMeLine.h:160
bool _useIntensityForRho
Definition: vpMeLine.h:166
double alpha
Definition: vpMeSite.h:92
int i
Definition: vpMeSite.h:86
error that can be emited by ViSP classes.
Definition: vpException.h:71
void track(const vpImage< unsigned char > &Im)
Definition: vpMeLine.cpp:745
int mask_sign
Definition: vpMeSite.h:90
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
void leastSquare()
Definition: vpMeLine.cpp:263
static const vpColor red
Definition: vpColor.h:180
void display(const vpImage< unsigned char > &I, vpColor col)
Definition: vpMeLine.cpp:222
double ifloat
Definition: vpMeSite.h:88
double rho
Definition: vpMeLine.h:159
virtual ~vpMeLine()
Definition: vpMeLine.cpp:134
void set_i(const double ii)
Definition: vpImagePoint.h:167
void computeRhoTheta(const vpImage< unsigned char > &I)
Definition: vpMeLine.cpp:820
std::list< vpMeSite > list
Definition: vpMeTracker.h:74
Error that can be emited by the vpTracker class and its derivates.
double getSampleStep() const
Definition: vpMe.h:285
void updateDelta()
Definition: vpMeLine.cpp:704
int outOfImage(int i, int j, int half, int row, int cols)
static void displayArrow(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1)
void getExtremities(vpImagePoint &ip1, vpImagePoint &ip2)
Definition: vpMeLine.cpp:968
double theta
Definition: vpMeLine.h:159
static double sqr(double x)
Definition: vpMath.h:108
void sample(const vpImage< unsigned char > &image)
Definition: vpMeLine.cpp:147
Class that tracks in an image a line moving edges.
Definition: vpMeLine.h:151
void suppressPoints()
Definition: vpMeLine.cpp:476
double get_j() const
Definition: vpImagePoint.h:215
double delta_1
Definition: vpMeLine.h:160
void setDisplay(vpMeSiteDisplayType select)
Definition: vpMeSite.h:137
#define vpCDEBUG(level)
Definition: vpDebug.h:511
void track(const vpImage< unsigned char > &I)
Track sampled pixels.
Contains abstract elements for a Distance to Feature type feature.
Definition: vpMeTracker.h:65
void initTracking(const vpImage< unsigned char > &I)
Definition: vpMeLine.cpp:234
double a
Parameter a of the line equation a*i + b*j + c = 0.
Definition: vpMeLine.h:174
void setState(const vpMeSiteState &flag)
Definition: vpMeSite.h:174
vpMeSite PExt[2]
Definition: vpMeLine.h:157
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)
#define vpDERROR_TRACE
Definition: vpDebug.h:464
int j
Definition: vpMeSite.h:86
unsigned int getHeight() const
Definition: vpImage.h:178
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
double b
Parameter b of the line equation a*i + b*j + c = 0.
Definition: vpMeLine.h:175
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
int sign
Definition: vpMeLine.h:162
void initTracking(const vpImage< unsigned char > &I)
double angle_1
Definition: vpMeLine.h:161
static bool intersection(const vpMeLine &line1, const vpMeLine &line2, vpImagePoint &ip)
Definition: vpMeLine.cpp:989
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)
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 seekExtremities(const vpImage< unsigned char > &I)
Definition: vpMeLine.cpp:549
void eye()
Definition: vpMatrix.cpp:360
virtual void display(const vpImage< unsigned char > &I, vpColor col)=0
static const vpColor blue
Definition: vpColor.h:186