ViSP  2.9.0
vpMbtMeLine.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMbtMeLine.cpp 4649 2014-02-07 14:57:11Z 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 
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 
80 {
81  list.clear();
82 }
83 
96 void
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 
114  a = cos(theta);
115  b = sin(theta);
116  c = -rho;
117 
118  double d = sqrt(vpMath::sqr(ip1.get_i()-ip2.get_i())+vpMath::sqr(ip1.get_j()-ip2.get_j())) ;
119 
120  expecteddensity = d / (double)me->getSampleStep();
121 
122  delta = - theta + M_PI/2.0;
123  normalizeAngle(delta);
124  delta_1 = delta;
125 
126  sample(I) ;
127 
129  }
130  catch(...)
131  {
132 // vpERROR_TRACE("Error caught") ;
133  throw ;
134  }
135  vpCDEBUG(1) <<" end vpMeLine::initTracking()"<<std::endl ;
136 }
137 
138 
145 void
146 vpMbtMeLine::sample(const vpImage<unsigned char>& I)
147 {
148  int rows = (int)I.getHeight() ;
149  int cols = (int)I.getWidth() ;
150  double n_sample;
151 
152  //if (me->getSampleStep==0)
153  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon())
154  {
155  vpERROR_TRACE("function called with sample step = 0") ;
157  "sample step = 0")) ;
158  }
159 
160  // i, j portions of the line_p
161  double diffsi = PExt[0].ifloat-PExt[1].ifloat;
162  double diffsj = PExt[0].jfloat-PExt[1].jfloat;
163 
164  double length_p = sqrt((vpMath::sqr(diffsi)+vpMath::sqr(diffsj)));
165 
166  // number of samples along line_p
167  n_sample = length_p/(double)me->getSampleStep();
168 
169  double stepi = diffsi/(double)n_sample;
170  double stepj = diffsj/(double)n_sample;
171 
172  // Choose starting point
173  double is = PExt[1].ifloat;
174  double js = PExt[1].jfloat;
175 
176  // Delete old list
177  list.clear();
178 
179  // sample positions at i*me->getSampleStep() interval along the
180  // line_p, starting at PSiteExt[0]
181 
182  vpImagePoint ip;
183  for(int i=0; i<=vpMath::round(n_sample); i++)
184  {
185  // If point is in the image, add to the sample list
186  if(!outOfImage(vpMath::round(is), vpMath::round(js), 0, rows, cols))
187  {
188  vpMeSite pix ; //= list.value();
189  pix.init((int)is, (int)js, delta, 0, sign) ;
190 
191  pix.track(I,me,0);
192 
194 
195  if(vpDEBUG_ENABLE(3))
196  {
197  ip.set_i( is );
198  ip.set_j( js );
200  }
201 
202  list.push_back(pix);
203  }
204  is += stepi;
205  js += stepj;
206 
207  }
208 
209  vpCDEBUG(1) << "end vpMeLine::sample() : ";
210  vpCDEBUG(1) << n_sample << " point inserted in the list " << std::endl ;
211 }
212 
213 
219 void
220 vpMbtMeLine::suppressPoints(const vpImage<unsigned char> & /*I*/)
221 {
222  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ){
223  vpMeSite s = *it;//current reference pixel
224 
225  if (fabs(sin(theta)) > 0.9) // Vertical line management
226  {
227  if ((s.i < imin) ||(s.i > imax))
228  {
230  }
231  }
232 
233  else if (fabs(cos(theta)) > 0.9) // Horizontal line management
234  {
235  if ((s.j < jmin) || (s.j > jmax))
236  {
238  }
239  }
240 
241  else
242  {
243  if ((s.i < imin) ||(s.i > imax) || (s.j < jmin) || (s.j > jmax) )
244  {
246  }
247  }
248 
250  it = list.erase(it);
251  else
252  ++it;
253  }
254 }
255 
256 
262 void
263 vpMbtMeLine::seekExtremities(const vpImage<unsigned char> &I)
264 {
265  vpCDEBUG(1) <<"begin vpMeLine::sample() : "<<std::endl ;
266 
267  int rows = (int)I.getHeight() ;
268  int cols = (int)I.getWidth() ;
269  double n_sample;
270 
271  //if (me->getSampleStep()==0)
272  if (std::fabs(me->getSampleStep()) <= std::numeric_limits<double>::epsilon())
273  {
274 
275  vpERROR_TRACE("function called with sample step = 0") ;
276  throw(vpTrackingException(vpTrackingException::fatalError,"sample step = 0")) ;
277  }
278 
279  // i, j portions of the line_p
280  double diffsi = PExt[0].ifloat-PExt[1].ifloat;
281  double diffsj = PExt[0].jfloat-PExt[1].jfloat;
282 
283  double s = vpMath::sqr(diffsi)+vpMath::sqr(diffsj) ;
284 
285  double di = diffsi/sqrt(s) ; // pas de risque de /0 car d(P1,P2) >0
286  double dj = diffsj/sqrt(s) ;
287 
288  double length_p = sqrt(s); /*(vpMath::sqr(diffsi)+vpMath::sqr(diffsj))*/
289 
290  // number of samples along line_p
291  n_sample = length_p/(double)me->getSampleStep();
292  double sample_step = (double)me->getSampleStep();
293 
294  vpMeSite P ;
295  P.init((int) PExt[0].ifloat, (int)PExt[0].jfloat, delta_1, 0, sign) ;
297 
298  unsigned int memory_range = me->getRange() ;
299  me->setRange(1);
300 
301  for (int i=0 ; i < 3 ; i++)
302  {
303  P.ifloat = P.ifloat + di*sample_step ; P.i = (int)P.ifloat ;
304  P.jfloat = P.jfloat + dj*sample_step ; P.j = (int)P.jfloat ;
305 
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, 5, rows, 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) ;
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 
334  if ((P.i < imin) ||(P.i > imax) || (P.j < jmin) || (P.j > jmax) )
335  {
337  }
338 
339  else
340  if(!outOfImage(P.i, P.j, 5, rows, cols))
341  {
342  P.track(I,me,false) ;
343 
345  {
346  list.push_back(P);
348  }
349  else
351  }
352  }
353 
354  me->setRange(memory_range);
355 
356  vpCDEBUG(1) <<"end vpMeLine::sample() : " ;
357  vpCDEBUG(1) << n_sample << " point inserted in the list " << std::endl ;
358 }
359 
370 void
371 vpMbtMeLine::reSample(const vpImage<unsigned char> &I)
372 {
373  double d = sqrt(vpMath::sqr(PExt[0].ifloat-PExt[1].ifloat)+vpMath::sqr(PExt[0].jfloat-PExt[1].jfloat)) ;
374 
375  unsigned int n = numberOfSignal() ;
376  double expected_density = d / (double)me->getSampleStep();
377 
378  if ((double)n<0.5*expected_density && n > 0)
379  {
380  double delta_new = delta;
381  delta = delta_1;
382  sample(I) ;
383  delta = delta_new;
384  // 2. On appelle ce qui n'est pas specifique
385  {
387  }
388  }
389 }
390 
391 
404 void
405 vpMbtMeLine::reSample(const vpImage<unsigned char> &I, vpImagePoint ip1, vpImagePoint ip2)
406 {
407  double d = sqrt(vpMath::sqr(ip1.get_i()-ip2.get_i())+vpMath::sqr(ip1.get_j()-ip2.get_j())) ;
408 
409  size_t n = list.size();
410  expecteddensity = d / (double)me->getSampleStep();
411 
412  if ((double)n<0.5*expecteddensity && n > 0)
413  {
414  double delta_new = delta;
415  delta = delta_1;
416  PExt[0].ifloat = (float)ip1.get_i() ;
417  PExt[0].jfloat = (float)ip1.get_j() ;
418  PExt[1].ifloat = (float)ip2.get_i() ;
419  PExt[1].jfloat = (float)ip2.get_j() ;
420  sample(I) ;
421  delta = delta_new;
422  vpMeTracker::track(I) ;
423  }
424 }
425 
429 void
430 vpMbtMeLine::updateDelta()
431 {
432  vpMeSite p_me ;
433 
434  double diff = 0;
435 
436  //if(fabs(theta) == M_PI )
437  if(std::fabs(std::fabs(theta) - M_PI) <= vpMath::maximum(std::fabs(theta), (double)M_PI)*std::numeric_limits<double>::epsilon() )
438  {
439  theta = 0 ;
440  }
441 
442  diff = fabs(theta - theta_1);
443  if (diff > M_PI/2.0)
444  sign *= -1;
445 
446  theta_1 = theta;
447 
448  delta = - theta + M_PI/2.0;
449  normalizeAngle(delta);
450 
451  for(std::list<vpMeSite>::iterator it=list.begin(); it!=list.end(); ++it){
452  p_me = *it;
453  p_me.alpha = delta ;
454  p_me.mask_sign = sign;
455  *it = p_me;
456  }
457  delta_1 = delta;
458 }
459 
465 void
467 {
468  // 2. On appelle ce qui n'est pas specifique
469  try
470  {
472  }
473  catch(...)
474  {
475  throw ;
476  }
477 
478  // supression des points rejetes par les ME
479  // suppressPoints(I);
480  // setExtremities();
481 }
482 
483 
491 void
492 vpMbtMeLine::updateParameters(const vpImage<unsigned char> &I, double rho_, double theta_)
493 {
494  this->rho = rho_;
495  this->theta = theta_;
496  a = cos(theta);
497  b = sin(theta);
498  c = -rho;
499  // recherche de point aux extremite de la droites
500  // dans le cas d'un glissement
501  suppressPoints(I);
502  seekExtremities(I);
503  suppressPoints(I);
504  setExtremities();
505  //reechantillonage si necessaire
506  reSample(I);
507 
508  // remet a jour l'angle delta pour chaque point de la liste
509  updateDelta();
510 }
511 
512 
522 void
524  double rho_, double theta_)
525 {
526  this->rho = rho_;
527  this->theta = theta_;
528  a = cos(theta);
529  b = sin(theta);
530  c = -rho;
531  // recherche de point aux extremite de la droites
532  // dans le cas d'un glissement
533  suppressPoints(I);
534  seekExtremities(I);
535  suppressPoints(I);
536  setExtremities();
537  //reechantillonage si necessaire
538  reSample(I,ip1,ip2);
539 
540  // remet a jour l'angle delta pour chaque point de la liste
541  updateDelta();
542 }
543 
544 
548 void
549 vpMbtMeLine::setExtremities()
550 {
551  double i_min = +1e6 ;
552  double j_min = +1e6;
553  double i_max = -1 ;
554  double j_max = -1 ;
555 
556  // Loop through list of sites to track
557  for(std::list<vpMeSite>::const_iterator it=list.begin(); it!=list.end(); ++it){
558  vpMeSite s = *it;//current reference pixel
559  if (s.ifloat < i_min)
560  {
561  i_min = s.ifloat ;
562  j_min = s.jfloat ;
563  }
564 
565  if (s.ifloat > i_max)
566  {
567  i_max = s.ifloat ;
568  j_max = s.jfloat ;
569  }
570  }
571 
572  if ( ! list.empty() )
573  {
574  PExt[0].ifloat = i_min ;
575  PExt[0].jfloat = j_min ;
576  PExt[1].ifloat = i_max ;
577  PExt[1].jfloat = j_max ;
578  }
579 
580  if (fabs(i_min-i_max) < 25)
581  {
582  for(std::list<vpMeSite>::const_iterator it=list.begin(); it!=list.end(); ++it){
583  vpMeSite s = *it;//current reference pixel
584  if (s.jfloat < j_min)
585  {
586  i_min = s.ifloat ;
587  j_min = s.jfloat ;
588  }
589 
590  if (s.jfloat > j_max)
591  {
592  i_max = s.ifloat ;
593  j_max = s.jfloat ;
594  }
595  }
596 
597  if (! list.empty())
598  {
599  PExt[0].ifloat = i_min ;
600  PExt[0].jfloat = j_min ;
601  PExt[1].ifloat = i_max ;
602  PExt[1].jfloat = j_max ;
603  }
604  bubbleSortJ();
605  }
606 
607  else
608  bubbleSortI();
609 }
610 
611 
612 static bool sortByI(const vpMeSite& s1, const vpMeSite& s2){
613  return (s1.ifloat > s2.ifloat);
614 }
615 
616 void
617 vpMbtMeLine::bubbleSortI()
618 {
619 #if 0
620  unsigned int nbElmt = list.size();
621  for (unsigned int pass = 1; pass < nbElmt; pass++)
622  {
623  list.front();
624  for (unsigned int i=0; i < nbElmt-pass; i++)
625  {
626  vpMeSite s1 = list.value() ;
627  vpMeSite s2 = list.nextValue() ;
628  if (s1.ifloat > s2.ifloat)
629  list.swapRight();
630  else
631  list.next();
632  }
633  }
634 #endif
635  list.sort(sortByI);
636 }
637 
638 
639 static bool sortByJ(const vpMeSite& s1, const vpMeSite& s2){
640  return (s1.jfloat > s2.jfloat);
641 }
642 
643 void
644 vpMbtMeLine::bubbleSortJ()
645 {
646 #if 0
647  unsigned int nbElmt = list.size();
648  for(unsigned int pass=1; pass < nbElmt; pass++)
649  {
650  list.front();
651  for (unsigned int i=0; i < nbElmt-pass; i++)
652  {
653  vpMeSite s1 = list.value() ;
654  vpMeSite s2 = list.nextValue() ;
655  if (s1.jfloat > s2.jfloat)
656  list.swapRight();
657  else
658  list.next();
659  }
660  }
661 #endif
662  list.sort(sortByJ);
663 }
664 
665 
666 void
667 vpMbtMeLine::findSignal(const vpImage<unsigned char>& I, const vpMe *p_me, double *conv)
668 {
669  vpImagePoint itest(PExt[0].ifloat+(PExt[1].ifloat-PExt[0].ifloat)/2, PExt[0].jfloat+(PExt[1].jfloat-PExt[0].jfloat)/2);
670 
671  vpMeSite pix ; //= list.value();
672  pix.init(itest.get_i(), itest.get_j(), delta, 0, sign);
673 
674  vpMeSite *list_query_pixels;
675 // double convolution = 0;
676  unsigned int range = p_me->getRange();
677 
678  list_query_pixels = pix.getQueryList(I, (int)range);
679 
681  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);
682  vpDisplay::displayCross(I,vpImagePoint(list_query_pixels[0].ifloat,list_query_pixels[0].jfloat),5,vpColor::orange,3);
683 
684  for(unsigned int n = 0 ; n < 2 * range + 1 ; n++)
685  {
686  conv[n] = list_query_pixels[n].convolution(I, p_me);
687  }
688  delete [] list_query_pixels;
689 }
690 
691 #endif
692 
unsigned int getRange() const
Definition: vpMe.h:236
void init()
Definition: vpMeSite.cpp:73
double get_i() const
Definition: vpImagePoint.h:194
unsigned int getWidth() const
Definition: vpImage.h:159
double jfloat
Definition: vpMeSite.h:100
unsigned int numberOfSignal()
#define vpERROR_TRACE
Definition: vpDebug.h:395
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
void track(const vpImage< unsigned char > &I)
int outOfImage(int i, int j, int half, int rows, int cols)
double alpha
Definition: vpMeSite.h:104
int i
Definition: vpMeSite.h:98
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
void initTracking(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, double rho, double theta)
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:205
double expecteddensity
Definition: vpMbtMeLine.h:74
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:158
std::list< vpMeSite > list
Definition: vpMeTracker.h:80
Error that can be emited by the vpTracker class and its derivates.
void updateParameters(const vpImage< unsigned char > &I, double rho, double theta)
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:169
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
vpMe * me
Moving edges initialisation parameters.
Definition: vpMeTracker.h:82
void initTracking(const vpImage< unsigned char > &I)
unsigned int getHeight() const
Definition: vpImage.h:150
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
virtual void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)=0
void setRange(const unsigned int &r)
Definition: vpMe.h:229
double getSampleStep() const
Definition: vpMe.h:278
vpMeSite::vpMeSiteDisplayType selectDisplay
Definition: vpMeTracker.h:87
static const vpColor blue
Definition: vpColor.h:173