ViSP  2.8.0
vpDot.cpp
1 /****************************************************************************
2  *
3  * $Id: vpDot.cpp 4317 2013-07-17 09:40:17Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 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  * Track a white dot.
36  *
37  * Authors:
38  * Eric Marchand
39  * Fabien Spindler
40  * Aurelien Yol
41  *
42  *****************************************************************************/
43 
44 /*
45  \file vpDot.cpp
46  \brief Track a white dot
47 */
48 
49 #include <visp/vpDot.h>
50 
51 #include <visp/vpDisplay.h>
52 #include <visp/vpColor.h>
53 
54 // exception handling
55 #include <visp/vpTrackingException.h>
56 #include <vector>
57 
58 /*
59  \class vpDot
60  \brief Track a white dot
61 */
62 
63 /* spiral size for the dot search */
64 const unsigned int vpDot::SPIRAL_SEARCH_SIZE = 350;
65 
72 void vpDot::init()
73 {
74  cog.set_u(0);
75  cog.set_v(0);
76 
77  compute_moment = false ;
78  graphics = false ;
79  thickness = 1;
80  maxDotSizePercentage = 0.25 ; // 25 % of the image size
81 
82  mean_gray_level = 0;
83  gray_level_min = 128;
84  gray_level_max = 255;
85  grayLevelPrecision = 0.85;
86  gamma = 1.5 ;
87 
88  m00 = m11 = m02 = m20 = m10 = m01 = mu11 = mu02 = mu20 = 0 ;
89 
90  connexityType = CONNEXITY_4;
91 
92  u_min = u_max = v_min = v_max = 0;
93 
94  gray_level_out = 0;
95  nbMaxPoint = 0;
96 }
97 
99 {
100  init() ;
101 }
102 
109 {
110  init() ;
111 
112  cog = ip;
113 }
114 
119 {
120  *this = d ;
121 }
122 
127 {
128 
129  ip_connexities_list.clear() ;
130 }
131 
135 vpDot&
137 {
138  ip_edges_list = d.ip_edges_list;
139  ip_connexities_list = d.ip_connexities_list;
140  connexityType = d.connexityType;
141  cog = d.getCog();
142 
143  u_min = d.u_min;
144  v_min = d.v_min;
145  u_max = d.u_max;
146  v_max = d.v_max;
147 
148  graphics = d.graphics ;
149  thickness = d.thickness;
150  maxDotSizePercentage = d.maxDotSizePercentage;
151  gray_level_out = d.gray_level_out;
152  mean_gray_level = d.mean_gray_level ;
153  gray_level_min = d.gray_level_min ;
154  gray_level_max = d.gray_level_max ;
155  grayLevelPrecision = d.grayLevelPrecision;
156  gamma = d.gamma;
157  compute_moment = d.compute_moment ;
158  nbMaxPoint = d.nbMaxPoint;
159 
160  m00 = d.m00;
161  m01 = d.m01;
162  m10 = d.m10;
163  m11 = d.m11;
164  m02 = d.m02;
165  m20 = d.m20;
166 
167  mu11 = d.mu11;
168  mu20 = d.mu20;
169  mu02 = d.mu02;
170 
171  return *this ;
172 }
173 
174 bool
176 {
177  return ( cog != d.getCog() );
178 }
179 
180 bool
182 {
183  return ( cog == d.getCog() );
184 }
185 
197 void
198 vpDot::setGrayLevelOut()
199 {
200  if (gray_level_min == 0) {
201  if (gray_level_max == 255) {
202  // gray_level_min = 0 and gray_level_max = 255: this should not occur
203  vpERROR_TRACE("Unable to choose a good \"out\" level") ;
205  "Unable to choose a good \"out\" level")) ;
206  }
207  gray_level_out = static_cast<unsigned char>(gray_level_max + 1u);
208  }
209 }
210 
228 bool vpDot::connexe(const vpImage<unsigned char>& I,unsigned int u,unsigned int v,
229  double &mean_value, double &u_cog, double &v_cog, double &n)
230 {
231  std::vector<bool> checkTab(I.getWidth()*I.getHeight(),false);
232  return connexe(I,u,v,mean_value,u_cog,v_cog,n,checkTab);
233 }
251 bool vpDot::connexe(const vpImage<unsigned char>& I,unsigned int u,unsigned int v,
252  double &mean_value, double &u_cog, double &v_cog, double &n,std::vector<bool> &checkTab)
253 {
254 
255  unsigned int width = I.getWidth();
256  unsigned int height= I.getHeight();
257 
258  // Test if we are in the image
259  if ( (u >= width) || (v >= height) )
260  {
261  //std::cout << "out of bound" << std::endl;
262  return false;
263  }
264 
265  if(checkTab[u + v*I.getWidth()])
266  return true;
267 
268  vpImagePoint ip;
269  ip.set_u(u);
270  ip.set_v(v);
271 
272  if (I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
273  {
274  checkTab[v*I.getWidth() + u] = true;
275 
276  ip_connexities_list.push_back(ip);
277 
278  u_cog += u ;
279  v_cog += v ;
280  n+=1 ;
281 
282  if (n > nbMaxPoint) {
283  vpERROR_TRACE("Too many point %lf (%lf%% of image size). "
284  "This threshold can be modified using the setMaxDotSize() "
285  "method.",
286  n, n / (I.getWidth() * I.getHeight()),
287  nbMaxPoint, maxDotSizePercentage) ;
288 
290  "Dot to big")) ;
291  }
292 
293  // Bounding box update
294  if (u < this->u_min) this->u_min = u;
295  if (u > this->u_max) this->u_max = u;
296  if (v < this->v_min) this->v_min = v;
297  if (v > this->v_max) this->v_max = v;
298 
299  // Mean value of the dot intensities
300  mean_value = (mean_value *(n-1) + I[v][u]) / n;
301  if (compute_moment==true)
302  {
303  m00++ ;
304  m10 += u ;
305  m01 += v ;
306  m11 += (u*v) ;
307  m20 += u*u ;
308  m02 += v*v ;
309  }
310  }
311  else
312  {
313  //std::cout << "not in" << std::endl;
314  return false;
315  }
316 
317  bool edge = false;
318 
319  //if((int)u-1 >= 0)
320  if(u >= 1)
321  if(!checkTab[u-1 + v*I.getWidth()])
322  if(!connexe(I,u-1,v, mean_value,u_cog,v_cog, n, checkTab))
323  edge = true;
324 
325  if(u+1 < I.getWidth())
326  if(!checkTab[u+1+v*I.getWidth()])
327  if(!connexe(I,u+1,v,mean_value,u_cog, v_cog, n, checkTab))
328  edge = true;
329 
330  if(v >= 1)
331  if(!checkTab[u+(v-1)*I.getWidth()])
332  if(!connexe(I,u, v-1,mean_value,u_cog, v_cog, n, checkTab))
333  edge = true;
334 
335  if(v+1 < I.getHeight())
336  if(!checkTab[u+(v+1)*I.getWidth()])
337  if(!connexe(I,u,v+1,mean_value,u_cog, v_cog, n, checkTab))
338  edge = true;
339 
340  if (connexityType == CONNEXITY_8) {
341  if(v >= 1 && u >= 1)
342  if(!checkTab[u-1+(v-1)*I.getWidth()])
343  if(!connexe(I,u-1,v-1,mean_value,u_cog, v_cog, n, checkTab))
344  edge = true;
345 
346  if(v >= 1 && u+1 < I.getWidth())
347  if(!checkTab[u+1+(v-1)*I.getWidth()])
348  if(!connexe(I,u+1,v-1,mean_value,u_cog, v_cog, n, checkTab))
349  edge = true;
350 
351  if(v+1 < I.getHeight() && u >= 1)
352  if(!checkTab[u-1+(v+1)*I.getWidth()])
353  if(!connexe(I,u-1,v+1,mean_value, u_cog, v_cog, n, checkTab))
354  edge = true;
355 
356  if(v+1 < I.getHeight() && u+1 < I.getWidth())
357  if(!checkTab[u+1+(v+1)*I.getWidth()])
358  if(!connexe(I,u+1,v+1,mean_value,u_cog, v_cog, n, checkTab))
359  edge = true;
360  }
361 
362  if(edge){
363  ip_edges_list.push_back(ip);
364  if (graphics==true)
365  {
366  vpImagePoint ip_(ip);
367  for(unsigned int t=0; t<thickness; t++) {
368  ip_.set_u(ip.get_u() + t);
370  }
371  //vpDisplay::flush(I);
372  }
373  }
374 
375  return true;
376 }
377 
397 void
398 vpDot::COG(const vpImage<unsigned char> &I, double& u, double& v)
399 {
400  // Set the maximal number of points considering the maximal dot size
401  // image percentage
402  nbMaxPoint = (I.getWidth() * I.getHeight()) * maxDotSizePercentage;
403 
404  // segmentation de l'image apres seuillage
405  // (etiquetage des composante connexe)
406  if (compute_moment)
407  m00 = m11 = m02 = m20 = m10 = m01 = mu11 = mu20 = mu02 = 0;
408 
409  double u_cog = 0 ;
410  double v_cog = 0 ;
411  double npoint = 0 ;
412  this->mean_gray_level = 0 ;
413 
414  ip_connexities_list.clear() ;
415  ip_edges_list.clear();
416 
417  // Initialise the boundig box
418  this->u_min = I.getWidth();
419  this->u_max = 0;
420  this->v_min = I.getHeight();
421  this->v_max = 0;
422 
423 #if 0
424  // Original version
425  if ( connexe(I, (unsigned int)u, (unsigned int)v,
426  gray_level_min, gray_level_max,
427  mean_gray_level, u_cog, v_cog, npoint) == vpDot::out)
428  {
429  bool sol = false ;
430  unsigned int pas ;
431  for (pas = 2 ; pas <= 25 ; pas ++ )if (sol==false)
432  {
433  for (int k=-1 ; k <=1 ; k++) if (sol==false)
434  for (int l=-1 ; l <=1 ; l++) if (sol==false)
435  {
436  u_cog = 0 ;
437  v_cog = 0 ;
438  ip_connexities_list.clear() ;
439 
440  this->mean_gray_level = 0 ;
441  if (connexe(I, (unsigned int)(u+k*pas),(unsigned int)(v+l*pas),
442  gray_level_min, gray_level_max,
443  mean_gray_level, u_cog, v_cog, npoint) != vpDot::out)
444  {
445  sol = true ; u += k*pas ; v += l*pas ;
446  }
447  }
448  }
449  if (sol == false)
450  {
451  vpERROR_TRACE("Dot has been lost") ;
453  "Dot has been lost")) ;
454  }
455  }
456 #else
457  // If the dot is not found, search around using a spiral
458  if ( !connexe(I,(unsigned int)u,(unsigned int)v, mean_gray_level, u_cog, v_cog, npoint) )
459  {
460  bool sol = false ;
461 
462  unsigned int right = 1;
463  unsigned int botom = 1;
464  unsigned int left = 2;
465  unsigned int up = 2;
466  double u_ = u, v_ = v;
467  unsigned int k;
468 
469  // Spiral search from the center to find the nearest dot
470  while( (right < SPIRAL_SEARCH_SIZE) && (sol == false) ) {
471  for (k=1; k <= right; k++) if(sol==false) {
472  u_cog = 0 ;
473  v_cog = 0 ;
474  ip_connexities_list.clear() ;
475  ip_edges_list.clear();
476 
477  this->mean_gray_level = 0 ;
478  if ( connexe(I, (unsigned int)u_+k, (unsigned int)(v_),mean_gray_level, u_cog, v_cog, npoint) ) {
479  sol = true; u = u_+k; v = v_;
480  }
481  }
482  u_ += k;
483  right += 2;
484 
485  for (k=1; k <= botom; k++) if (sol==false) {
486  u_cog = 0 ;
487  v_cog = 0 ;
488  ip_connexities_list.clear() ;
489  ip_edges_list.clear();
490 
491  this->mean_gray_level = 0 ;
492 
493  if ( connexe(I, (unsigned int)(u_), (unsigned int)(v_+k),mean_gray_level, u_cog, v_cog, npoint) ) {
494  sol = true; u = u_; v = v_+k;
495  }
496  }
497  v_ += k;
498  botom += 2;
499 
500  for (k=1; k <= left; k++) if (sol==false) {
501  u_cog = 0 ;
502  v_cog = 0 ;
503  ip_connexities_list.clear() ;
504  ip_edges_list.clear();
505 
506  this->mean_gray_level = 0 ;
507 
508  if ( connexe(I, (unsigned int)(u_-k), (unsigned int)(v_),mean_gray_level,u_cog, v_cog, npoint) ) {
509  sol = true ; u = u_-k; v = v_;
510  }
511  }
512  u_ -= k;
513  left += 2;
514 
515  for (k=1; k <= up; k++) if(sol==false) {
516  u_cog = 0 ;
517  v_cog = 0 ;
518  ip_connexities_list.clear() ;
519  ip_edges_list.clear();
520 
521  this->mean_gray_level = 0 ;
522 
523  if ( connexe(I, (unsigned int)(u_), (unsigned int)(v_-k),mean_gray_level,u_cog, v_cog, npoint) ) {
524  sol = true ; u = u_; v = v_-k;
525  }
526  }
527  v_ -= k;
528  up += 2;
529  }
530 
531  if (sol == false) {
532  vpERROR_TRACE("Dot has been lost") ;
534  "Dot has been lost")) ;
535  }
536  }
537 
538 #endif
539 /*
540  vpImagePoint ip;
541  unsigned int i, j;
542  std::list<vpImagePoint>::iterator it;
543  for (it = ip_connexities_list.begin(); it != ip_connexities_list.end(); it ++) {
544  ip = *it;
545  i = (unsigned int) ip.get_i();
546  j = (unsigned int) ip.get_j();
547  I[i][j] = 255 ;
548  }*/
549 
550  u_cog = u_cog/npoint ;
551  v_cog = v_cog/npoint ;
552 
553  u = u_cog ;
554  v = v_cog ;
555 
556  // Initialize the threshold for the next call to track()
557  double Ip = pow((double)this->mean_gray_level/255,1/gamma);
558 
559  if(Ip - (1 - grayLevelPrecision)<0){
560  gray_level_min = 0 ;
561  }
562  else{
563  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
564  if (gray_level_min > 255)
565  gray_level_min = 255;
566  }
567  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
568  if (gray_level_max > 255)
569  gray_level_max = 255;
570 
571  //vpCTRACE << "gray_level_min: " << gray_level_min << std::endl;
572  //vpCTRACE << "gray_level_max: " << gray_level_max << std::endl;
573 
574  if (npoint < 5)
575  {
576  vpERROR_TRACE("Dot to small") ;
578  "Dot to small")) ;
579  }
580 
581  if (npoint > nbMaxPoint)
582  {
583  vpERROR_TRACE("Too many point %lf (%lf%%). Max allowed is %lf (%lf%%). This threshold can be modified using the setMaxDotSize() method.",
584  npoint, npoint / (I.getWidth() * I.getHeight()),
585  nbMaxPoint, maxDotSizePercentage) ;
586 
588  "Dot to big")) ;
589  }
590 }
591 
604 void
605 vpDot::setMaxDotSize(double percentage)
606 {
607  if (percentage <= 0.0 || percentage > 1.0) {
608  // print a warning. We keep the default percentage
609  vpTRACE("Max dot size percentage is requested to be set to %lf.",
610  "Value should be in ]0:1]. Value will be set to %lf.",
611  percentage, maxDotSizePercentage);
612  }
613  else {
614  maxDotSizePercentage = percentage;
615  }
616 }
617 
641 void
643 {
644  while (vpDisplay::getClick(I, cog) != true) ;
645 
646  unsigned int i = (unsigned int)cog.get_i();
647  unsigned int j = (unsigned int)cog.get_j();
648 
649  double Ip = pow((double)I[i][j]/255, 1/gamma);
650 
651  if(Ip - (1 - grayLevelPrecision)<0){
652  gray_level_min = 0 ;
653  }
654  else{
655  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
656  if (gray_level_min > 255)
657  gray_level_min = 255;
658  }
659  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
660  if (gray_level_max > 255)
661  gray_level_max = 255;
662 
663  try {
664  track( I );
665  }
666  catch(...)
667  {
668  vpERROR_TRACE("Error caught") ;
669  throw ;
670  }
671 }
672 
696 void
698 {
699 
700  cog = ip ;
701 
702  unsigned int i = (unsigned int)cog.get_i();
703  unsigned int j = (unsigned int)cog.get_j();
704 
705  double Ip = pow((double)I[i][j]/255, 1/gamma);
706 
707  if(Ip - (1 - grayLevelPrecision)<0){
708  gray_level_min = 0 ;
709  }
710  else{
711  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
712  if (gray_level_min > 255)
713  gray_level_min = 255;
714  }
715  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
716  if (gray_level_max > 255)
717  gray_level_max = 255;
718  try {
719  track( I );
720  }
721  catch(...)
722  {
723  vpERROR_TRACE("Error caught") ;
724  throw ;
725  }
726 }
727 
755 void
757  unsigned int gray_level_min, unsigned int gray_level_max)
758 {
759 
760  cog = ip ;
761 
762  this->gray_level_min = gray_level_min;
763  this->gray_level_max = gray_level_max;
764 
765  try {
766  track( I );
767  }
768  catch(...)
769  {
770  vpERROR_TRACE("Error caught") ;
771  throw ;
772  }
773 }
774 
775 
790 void
792 {
793  try{
794  setGrayLevelOut();
795  double u = this->cog.get_u();
796  double v = this->cog.get_v();
797 
798  COG( I, u, v ) ;
799 
800  this->cog.set_u( u );
801  this->cog.set_v( v );
802 
803  if (compute_moment==true)
804  {
805  mu11 = m11 - u*m01;
806  mu02 = m02 - v*m01;
807  mu20 = m20 - u*m10;
808  }
809 
810  if (graphics) {
811  // display a red cross at the center of gravity's location in the image.
812  vpDisplay::displayCross(I, this->cog, 3*thickness+8, vpColor::red, thickness);
813  }
814 
815  }
816  catch(...)
817  {
818  vpERROR_TRACE("Error caught") ;
819  throw ;
820  }
821 }
822 
837 void
839 {
840  track( I ) ;
841 
842  cog = this->cog;
843 }
844 
853  unsigned int thickness)
854 {
855  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
856  std::list<vpImagePoint>::const_iterator it;
857 
858  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it)
859  {
860  vpDisplay::displayPoint(I, *it, color);
861  }
862 }
863 
881 void vpDot::setGrayLevelPrecision( const double & grayLevelPrecision )
882 {
883  double epsilon = 0.05;
884  if( grayLevelPrecision<epsilon )
885  {
886  this->grayLevelPrecision = epsilon;
887  }
888  else if( grayLevelPrecision>1 )
889  {
890  this->grayLevelPrecision = 1.0;
891  }
892  else
893  {
894  this->grayLevelPrecision = grayLevelPrecision;
895  }
896 }
897 
913  const std::list<vpImagePoint> &edges_list, vpColor color,
914  unsigned int thickness)
915 {
916  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
917  std::list<vpImagePoint>::const_iterator it;
918 
919  for (it = edges_list.begin(); it != edges_list.end(); ++it)
920  {
921  vpDisplay::displayPoint(I, *it, color);
922  }
923 }
924 
939 void vpDot::display(const vpImage<vpRGBa>& I,const vpImagePoint &cog,
940  const std::list<vpImagePoint> &edges_list, vpColor color,
941  unsigned int thickness)
942 {
943  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
944  std::list<vpImagePoint>::const_iterator it;
945 
946  for (it = edges_list.begin(); it != edges_list.end(); ++it)
947  {
948  vpDisplay::displayPoint(I, *it, color);
949  }
950 }
951 
952 
953 
double get_v() const
Definition: vpImagePoint.h:250
double mu20
Definition: vpDot.h:186
bool operator!=(const vpDot &d)
Definition: vpDot.cpp:175
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
Definition: vpDot.cpp:852
void setMaxDotSize(double percentage)
Definition: vpDot.cpp:605
double get_i() const
Definition: vpImagePoint.h:181
unsigned int getWidth() const
Definition: vpImage.h:159
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot.cpp:881
double m10
Definition: vpDot.h:147
#define vpERROR_TRACE
Definition: vpDebug.h:379
#define vpTRACE
Definition: vpDebug.h:401
Class to define colors available for display functionnalities.
Definition: vpColor.h:125
double get_u() const
Definition: vpImagePoint.h:239
void track(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:791
double m00
Definition: vpDot.h:133
double mu11
Definition: vpDot.h:181
double mu02
Definition: vpDot.h:191
double get_j() const
Definition: vpImagePoint.h:192
static const unsigned int SPIRAL_SEARCH_SIZE
Definition: vpDot.h:131
double m20
Definition: vpDot.h:163
double m11
Definition: vpDot.h:154
static const vpColor red
Definition: vpColor.h:167
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:69
vpImagePoint getCog() const
Definition: vpDot.h:227
double m01
Definition: vpDot.h:140
Error that can be emited by the vpTracker class and its derivates.
vpDot & operator=(const vpDot &d)
Copy operator.
Definition: vpDot.cpp:136
void set_u(const double u)
Definition: vpImagePoint.h:203
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void set_v(const double v)
Definition: vpImagePoint.h:214
double m02
Definition: vpDot.h:172
vpDot()
Definition: vpDot.cpp:98
This tracker is meant to track a dot (connected pixels with same gray level) on a vpImage...
Definition: vpDot.h:118
unsigned int getHeight() const
Definition: vpImage.h:150
virtual bool getClick(bool blocking=true)=0
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:92
bool operator==(const vpDot &d)
Definition: vpDot.cpp:181
void initTracking(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:642
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
virtual ~vpDot()
Destructor.
Definition: vpDot.cpp:126