ViSP  2.10.0
vpMbtMeLine.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMbtMeLine.cpp 5216 2015-01-28 08:03:09Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Make the complete tracking of an object by using its CAD model
36  *
37  * Authors:
38  * Nicolas Melchior
39  * Romain Tallonneau
40  * Eric Marchand
41  *
42  *****************************************************************************/
43 #include <visp/vpConfig.h>
44 #ifndef DOXYGEN_SHOULD_SKIP_THIS
45 
50 #include <cmath> // std::fabs
51 #include <limits> // numeric_limits
52 
53 #include <visp/vpMbtMeLine.h>
54 #include <visp/vpTrackingException.h>
55 #include <visp/vpRobust.h>
56 
58 static void
59 normalizeAngle(double &delta)
60 {
61  while (delta > M_PI) { delta -= M_PI ; }
62  while (delta < -M_PI) { delta += M_PI ; }
63 }
64 
65 
69 vpMbtMeLine::vpMbtMeLine()
70  : rho(0.), theta(0.), theta_1(M_PI/2), delta(0.), delta_1(0), sign(1),
71  a(0.), b(0.), c(0.), imin(0), imax(0), jmin(0), jmax(0),
72  expecteddensity(0.)
73 {
74 }
75 
79 vpMbtMeLine::~vpMbtMeLine()
80 {
81  list.clear();
82 }
83 
96 void
97 vpMbtMeLine::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip1, const vpImagePoint &ip2,
98  double rho_, double theta_)
99 {
100  vpCDEBUG(1) <<" begin vpMeLine::initTracking()"<<std::endl ;
101 
102  try
103  {
104  // 1. On fait ce qui concerne les droites (peut etre vide)
105  // Points extremites
106  PExt[0].ifloat = (float)ip1.get_i() ;
107  PExt[0].jfloat = (float)ip1.get_j() ;
108  PExt[1].ifloat = (float)ip2.get_i() ;
109  PExt[1].jfloat = (float)ip2.get_j() ;
110 
111  this->rho = rho_;
112  this->theta = theta_;
113  theta_1 = theta_;
114 
115  a = cos(theta);
116  b = sin(theta);
117  c = -rho;
118 
119  delta = - theta + M_PI/2.0;
120  normalizeAngle(delta);
121  delta_1 = delta;
122 
123  sample(I) ;
124  expecteddensity = (double)list.size();
125 
127  }
128  catch(vpException &e)
129  {
130  throw e;
131  }
132  vpCDEBUG(1) <<" end vpMeLine::initTracking()"<<std::endl ;
133 }
134 
135 
142 void
143 vpMbtMeLine::sample(const vpImage<unsigned char>& I)
144 {
145  int rows = (int)I.getHeight() ;
146  int cols = (int)I.getWidth() ;
147  double n_sample;
148 
149  //if (me->getSampleStep==0)
150  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon())
151  {
153  "Function vpMbtMeLine::sample() called with moving-edges sample step = 0")) ;
154  }
155 
156  // i, j portions of the line_p
157  double diffsi = PExt[0].ifloat-PExt[1].ifloat;
158  double diffsj = PExt[0].jfloat-PExt[1].jfloat;
159 
160  double length_p = sqrt((vpMath::sqr(diffsi)+vpMath::sqr(diffsj)));
161 
162  // number of samples along line_p
163  n_sample = length_p/(double)me->getSampleStep();
164 
165  double stepi = diffsi/(double)n_sample;
166  double stepj = diffsj/(double)n_sample;
167 
168  // Choose starting point
169  double is = PExt[1].ifloat;
170  double js = PExt[1].jfloat;
171 
172  // Delete old list
173  list.clear();
174 
175  // sample positions at i*me->getSampleStep() interval along the
176  // line_p, starting at PSiteExt[0]
177 
178  vpImagePoint ip;
179  for(int i=0; i<=vpMath::round(n_sample); i++)
180  {
181  // If point is in the image, add to the sample list
182  if(!outOfImage(vpMath::round(is), vpMath::round(js), (int)(me->getRange()+me->getMaskSize()+1), (int)rows, (int)cols))
183  {
184  vpMeSite pix ; //= list.value();
185  pix.init((int)is, (int)js, delta, 0, sign) ;
186 
187  pix.track(I, me, false);
188 
189  pix.setDisplay(selectDisplay) ;
190 
191  if(vpDEBUG_ENABLE(3))
192  {
193  ip.set_i( is );
194  ip.set_j( js );
196  }
197 
198  list.push_back(pix);
199  }
200  is += stepi;
201  js += stepj;
202 
203  }
204 
205  vpCDEBUG(1) << "end vpMeLine::sample() : ";
206  vpCDEBUG(1) << list.size() << " point inserted in the list " << std::endl ;
207 }
208 
209 
215 void
216 vpMbtMeLine::suppressPoints(const vpImage<unsigned char> & I)
217 {
218  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ){
219  vpMeSite s = *it;//current reference pixel
220 
221  if (fabs(sin(theta)) > 0.9) // Vertical line management
222  {
223  if ((s.i < imin) ||(s.i > imax))
224  {
226  }
227  }
228 
229  else if (fabs(cos(theta)) > 0.9) // Horizontal line management
230  {
231  if ((s.j < jmin) || (s.j > jmax))
232  {
234  }
235  }
236 
237  else
238  {
239  if ((s.i < imin) ||(s.i > imax) || (s.j < jmin) || (s.j > jmax) )
240  {
242  }
243 
244  }
245 
246  if (outOfImage(s.i, s.j, (int)(me->getRange()+me->getMaskSize()+1), (int)I.getHeight(), (int)I.getWidth()))
247  {
249  }
250 
252  it = list.erase(it);
253  else
254  ++it;
255  }
256 }
257 
258 
264 void
265 vpMbtMeLine::seekExtremities(const vpImage<unsigned char> &I)
266 {
267  vpCDEBUG(1) <<"begin vpMeLine::sample() : "<<std::endl ;
268 
269  int rows = (int)I.getHeight() ;
270  int cols = (int)I.getWidth() ;
271  double n_sample;
272 
273  //if (me->getSampleStep()==0)
274  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon())
275  {
277  "Function called with sample step = 0")) ;
278  }
279 
280  // i, j portions of the line_p
281  double diffsi = PExt[0].ifloat-PExt[1].ifloat;
282  double diffsj = PExt[0].jfloat-PExt[1].jfloat;
283 
284  double s = vpMath::sqr(diffsi)+vpMath::sqr(diffsj) ;
285 
286  double di = diffsi/sqrt(s) ; // pas de risque de /0 car d(P1,P2) >0
287  double dj = diffsj/sqrt(s) ;
288 
289  double length_p = sqrt(s); /*(vpMath::sqr(diffsi)+vpMath::sqr(diffsj))*/
290 
291  // number of samples along line_p
292  n_sample = length_p/(double)me->getSampleStep();
293  double sample_step = (double)me->getSampleStep();
294 
295  vpMeSite P ;
296  P.init((int) PExt[0].ifloat, (int)PExt[0].jfloat, delta_1, 0, sign) ;
297  P.setDisplay(selectDisplay) ;
298 
299  unsigned int memory_range = me->getRange() ;
300  me->setRange(1);
301 
302  for (int i=0 ; i < 3 ; i++)
303  {
304  P.ifloat = P.ifloat + di*sample_step ; P.i = (int)P.ifloat ;
305  P.jfloat = P.jfloat + dj*sample_step ; P.j = (int)P.jfloat ;
306 
307  if ((P.i < imin) ||(P.i > imax) || (P.j < jmin) || (P.j > jmax) )
308  {
310  }
311  else
312  if(!outOfImage(P.i, P.j, (int)(me->getRange()+me->getMaskSize()+1), (int)rows, (int)cols))
313  {
314  P.track(I,me,false) ;
315 
317  {
318  list.push_back(P);
320  }
321  else
323  }
324  }
325 
326  P.init((int) PExt[1].ifloat, (int)PExt[1].jfloat, delta_1, 0, sign) ;
327  P.setDisplay(selectDisplay) ;
328  for (int i=0 ; i < 3 ; i++)
329  {
330  P.ifloat = P.ifloat - di*sample_step ; P.i = (int)P.ifloat ;
331  P.jfloat = P.jfloat - dj*sample_step ; P.j = (int)P.jfloat ;
332 
333  if ((P.i < imin) ||(P.i > imax) || (P.j < jmin) || (P.j > jmax) )
334  {
336  }
337 
338  else
339  if(!outOfImage(P.i, P.j, (int)(me->getRange()+me->getMaskSize()+1), (int)rows, (int)cols))
340  {
341  P.track(I,me,false) ;
342 
344  {
345  list.push_back(P);
347  }
348  else
350  }
351  }
352 
353  me->setRange(memory_range);
354 
355  vpCDEBUG(1) <<"end vpMeLine::sample() : " ;
356  vpCDEBUG(1) << n_sample << " point inserted in the list " << std::endl ;
357 }
358 
369 void
370 vpMbtMeLine::reSample(const vpImage<unsigned char> &I)
371 {
372  unsigned int n = numberOfSignal() ;
373 
374  if ((double)n<0.5*expecteddensity && n > 0)
375  {
376  double delta_new = delta;
377  delta = delta_1;
378  sample(I) ;
379  expecteddensity = (double)list.size();
380  delta = delta_new;
381  // 2. On appelle ce qui n'est pas specifique
382  {
384  }
385  }
386 }
387 
388 
401 void
402 vpMbtMeLine::reSample(const vpImage<unsigned char> &I, vpImagePoint ip1, vpImagePoint ip2)
403 {
404  size_t n = list.size();
405 
406  if ((double)n<0.5*expecteddensity /*&& n > 0*/) // n is always > 0
407  {
408  double delta_new = delta;
409  delta = delta_1;
410  PExt[0].ifloat = (float)ip1.get_i() ;
411  PExt[0].jfloat = (float)ip1.get_j() ;
412  PExt[1].ifloat = (float)ip2.get_i() ;
413  PExt[1].jfloat = (float)ip2.get_j() ;
414  sample(I) ;
415  expecteddensity = (double)list.size();
416  delta = delta_new;
417  vpMeTracker::track(I) ;
418  }
419 }
420 
424 void
425 vpMbtMeLine::updateDelta()
426 {
427  vpMeSite p_me ;
428 
429  double diff = 0;
430 
431  //if(fabs(theta) == M_PI )
432  if(std::fabs(std::fabs(theta) - M_PI) <= vpMath::maximum(std::fabs(theta), (double)M_PI)*std::numeric_limits<double>::epsilon() )
433  {
434  theta = 0 ;
435  }
436 
437  diff = fabs(theta - theta_1);
438  if (diff > M_PI/2.0)
439  sign *= -1;
440 
441  theta_1 = theta;
442 
443  delta = - theta + M_PI/2.0;
444  normalizeAngle(delta);
445 
446  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ++it){
447  p_me = *it;
448  p_me.alpha = delta ;
449  p_me.mask_sign = sign;
450  *it = p_me;
451  }
452  delta_1 = delta;
453 }
454 
460 void
461 vpMbtMeLine::track(const vpImage<unsigned char> &I)
462 {
463  // 2. On appelle ce qui n'est pas specifique
464  try
465  {
467  }
468  catch(vpException &e)
469  {
470  throw e;
471  }
472 
473  // supression des points rejetes par les ME
474  // suppressPoints(I);
475  // setExtremities();
476 }
477 
478 
486 void
487 vpMbtMeLine::updateParameters(const vpImage<unsigned char> &I, double rho_, double theta_)
488 {
489  this->rho = rho_;
490  this->theta = theta_;
491  a = cos(theta);
492  b = sin(theta);
493  c = -rho;
494  // recherche de point aux extremite de la droites
495  // dans le cas d'un glissement
496  suppressPoints(I);
497  seekExtremities(I);
498  suppressPoints(I);
499  setExtremities();
500  //reechantillonage si necessaire
501  reSample(I);
502 
503  // remet a jour l'angle delta pour chaque point de la liste
504  updateDelta();
505 }
506 
507 
517 void
518 vpMbtMeLine::updateParameters(const vpImage<unsigned char> &I, vpImagePoint ip1, vpImagePoint ip2,
519  double rho_, double theta_)
520 {
521  this->rho = rho_;
522  this->theta = theta_;
523  a = cos(theta);
524  b = sin(theta);
525  c = -rho;
526  // recherche de point aux extremite de la droites
527  // dans le cas d'un glissement
528  suppressPoints(I);
529  seekExtremities(I);
530  suppressPoints(I);
531  setExtremities();
532  //reechantillonage si necessaire
533  reSample(I,ip1,ip2);
534 
535  // remet a jour l'angle delta pour chaque point de la liste
536  updateDelta();
537 }
538 
539 
543 void
544 vpMbtMeLine::setExtremities()
545 {
546  double i_min = +1e6 ;
547  double j_min = +1e6;
548  double i_max = -1 ;
549  double j_max = -1 ;
550 
551  // Loop through list of sites to track
552  for(std::list<vpMeSite>::const_iterator it=list.begin(); it!=list.end(); ++it){
553  vpMeSite s = *it;//current reference pixel
554  if (s.ifloat < i_min)
555  {
556  i_min = s.ifloat ;
557  j_min = s.jfloat ;
558  }
559 
560  if (s.ifloat > i_max)
561  {
562  i_max = s.ifloat ;
563  j_max = s.jfloat ;
564  }
565  }
566 
567  if ( ! list.empty() )
568  {
569  PExt[0].ifloat = i_min ;
570  PExt[0].jfloat = j_min ;
571  PExt[1].ifloat = i_max ;
572  PExt[1].jfloat = j_max ;
573  }
574 
575  if (fabs(i_min-i_max) < 25)
576  {
577  for(std::list<vpMeSite>::const_iterator it=list.begin(); it!=list.end(); ++it){
578  vpMeSite s = *it;//current reference pixel
579  if (s.jfloat < j_min)
580  {
581  i_min = s.ifloat ;
582  j_min = s.jfloat ;
583  }
584 
585  if (s.jfloat > j_max)
586  {
587  i_max = s.ifloat ;
588  j_max = s.jfloat ;
589  }
590  }
591 
592  if (! list.empty())
593  {
594  PExt[0].ifloat = i_min ;
595  PExt[0].jfloat = j_min ;
596  PExt[1].ifloat = i_max ;
597  PExt[1].jfloat = j_max ;
598  }
599  bubbleSortJ();
600  }
601 
602  else
603  bubbleSortI();
604 }
605 
606 
607 static bool sortByI(const vpMeSite& s1, const vpMeSite& s2){
608  return (s1.ifloat > s2.ifloat);
609 }
610 
611 void
612 vpMbtMeLine::bubbleSortI()
613 {
614 #if 0
615  unsigned int nbElmt = list.size();
616  for (unsigned int pass = 1; pass < nbElmt; pass++)
617  {
618  list.front();
619  for (unsigned int i=0; i < nbElmt-pass; i++)
620  {
621  vpMeSite s1 = list.value() ;
622  vpMeSite s2 = list.nextValue() ;
623  if (s1.ifloat > s2.ifloat)
624  list.swapRight();
625  else
626  list.next();
627  }
628  }
629 #endif
630  list.sort(sortByI);
631 }
632 
633 
634 static bool sortByJ(const vpMeSite& s1, const vpMeSite& s2){
635  return (s1.jfloat > s2.jfloat);
636 }
637 
638 void
639 vpMbtMeLine::bubbleSortJ()
640 {
641 #if 0
642  unsigned int nbElmt = list.size();
643  for(unsigned int pass=1; pass < nbElmt; pass++)
644  {
645  list.front();
646  for (unsigned int i=0; i < nbElmt-pass; i++)
647  {
648  vpMeSite s1 = list.value() ;
649  vpMeSite s2 = list.nextValue() ;
650  if (s1.jfloat > s2.jfloat)
651  list.swapRight();
652  else
653  list.next();
654  }
655  }
656 #endif
657  list.sort(sortByJ);
658 }
659 
660 
661 void
662 vpMbtMeLine::findSignal(const vpImage<unsigned char>& I, const vpMe *p_me, double *conv)
663 {
664  vpImagePoint itest(PExt[0].ifloat+(PExt[1].ifloat-PExt[0].ifloat)/2, PExt[0].jfloat+(PExt[1].jfloat-PExt[0].jfloat)/2);
665 
666  vpMeSite pix ; //= list.value();
667  pix.init(itest.get_i(), itest.get_j(), delta, 0, sign);
668 
669  vpMeSite *list_query_pixels;
670 // double convolution = 0;
671  unsigned int range = p_me->getRange();
672 
673  list_query_pixels = pix.getQueryList(I, (int)range);
674 
676  vpDisplay::displayLine(I,vpImagePoint(list_query_pixels[0].ifloat,list_query_pixels[0].jfloat),vpImagePoint(list_query_pixels[2*range].ifloat,list_query_pixels[2*range].jfloat),vpColor::cyan);
677  vpDisplay::displayCross(I,vpImagePoint(list_query_pixels[0].ifloat,list_query_pixels[0].jfloat),5,vpColor::orange,3);
678 
679  for(unsigned int n = 0 ; n < 2 * range + 1 ; n++)
680  {
681  conv[n] = list_query_pixels[n].convolution(I, p_me);
682  }
683  delete [] list_query_pixels;
684 }
685 
686 #endif
687 
unsigned int getRange() const
Definition: vpMe.h:236
void init()
Definition: vpMeSite.cpp:73
double get_i() const
Definition: vpImagePoint.h:195
unsigned int getWidth() const
Definition: vpImage.h:161
double jfloat
Definition: vpMeSite.h:100
double convolution(const vpImage< unsigned char > &ima, const vpMe *me)
Definition: vpMeSite.cpp:312
Performs search in a given direction(normal) for a given distance(pixels) for a given 'site'...
Definition: vpMeSite.h:76
double alpha
Definition: vpMeSite.h:104
int i
Definition: vpMeSite.h:98
error that can be emited by ViSP classes.
Definition: vpException.h:76
Contains predetermined masks for sites and holds moving edges tracking parameters.
Definition: vpMe.h:70
int mask_sign
Definition: vpMeSite.h:102
#define vpDEBUG_ENABLE(level)
Definition: vpDebug.h:530
static const vpColor green
Definition: vpColor.h:170
static int round(const double x)
Definition: vpMath.h:228
double get_j() const
Definition: vpImagePoint.h:206
vpMeSiteState getState() const
Definition: vpMeSite.h:202
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:137
static const vpColor orange
Definition: vpColor.h:177
double ifloat
Definition: vpMeSite.h:100
void set_i(const double ii)
Definition: vpImagePoint.h:159
Error that can be emited by the vpTracker class and its derivates.
static const vpColor cyan
Definition: vpColor.h:176
static double sqr(double x)
Definition: vpMath.h:106
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void setDisplay(vpMeSiteDisplayType select)
Definition: vpMeSite.h:152
void track(const vpImage< unsigned char > &I)
Track sampled pixels.
vpMeSite * getQueryList(const vpImage< unsigned char > &I, const int range)
Definition: vpMeSite.cpp:229
void setState(const vpMeSiteState &flag)
Definition: vpMeSite.h:189
#define vpCDEBUG(level)
Definition: vpDebug.h:506
void set_j(const double jj)
Definition: vpImagePoint.h:170
int j
Definition: vpMeSite.h:98
void track(const vpImage< unsigned char > &im, const vpMe *me, const bool test_contraste=true)
Definition: vpMeSite.cpp:381
void initTracking(const vpImage< unsigned char > &I)
unsigned int getHeight() const
Definition: vpImage.h:152
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:93
virtual void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)=0
static const vpColor blue
Definition: vpColor.h:173