ViSP  2.6.2
vpDot.cpp
1 /****************************************************************************
2  *
3  * $Id: vpDot.cpp 3660 2012-03-29 10:41:21Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2012 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  maxDotSizePercentage = 0.25 ; // 25 % of the image size
80 
81  mean_gray_level = 0;
82  gray_level_min = 128;
83  gray_level_max = 255;
84  grayLevelPrecision = 0.85;
85  gamma = 1.5 ;
86 
87  m00 = m11 = m02 = m20 = m10 = m01 = mu11 = mu02 = mu20 = 0 ;
88 
89  connexityType = CONNEXITY_4;
90 
91  u_min = u_max = v_min = v_max = 0;
92 
93  gray_level_out = 0;
94  nbMaxPoint = 0;
95 }
96 
98 {
99  init() ;
100 }
101 
108 {
109  init() ;
110 
111  cog = ip;
112 }
113 
118 {
119 
120  *this = d ;
121 
122 }
123 
124 
129 {
130 
131  ip_connexities_list.clear() ;
132 }
133 
137 vpDot&
139 {
140  cog = d.getCog();
141 
142  graphics = d.graphics ;
143  mean_gray_level = d.mean_gray_level ;
144  gray_level_min = d.gray_level_min ;
145  gray_level_max = d.gray_level_max ;
146  grayLevelPrecision = d.grayLevelPrecision;
147  compute_moment = d.compute_moment ;
148 
149  maxDotSizePercentage = d.maxDotSizePercentage;
150 
151  m00 = d.m00;
152  m01 = d.m01;
153  m10 = d.m10;
154  m02 = d.m02;
155  m20 = d.m20;
156  mu11 = d.mu11;
157  mu20 = d.mu20;
158  mu02 = d.mu02;
159 
160  u_min = d.u_min;
161  v_min = d.v_min;
162  u_max = d.u_max;
163  v_max = d.v_max;
164 
165  gray_level_out = d.gray_level_out;
166  gamma = d.gamma;
167 
168  nbMaxPoint = d.nbMaxPoint;
169 
170  return *this ;
171 }
172 
173 bool
175 {
176  return ( cog != d.getCog() );
177 }
178 
179 bool
181 {
182  return ( cog == d.getCog() );
183 }
184 
196 void
197 vpDot::setGrayLevelOut()
198 {
199  if (gray_level_min == 0) {
200  if (gray_level_max == 255) {
201  // gray_level_min = 0 and gray_level_max = 255: this should not occur
202  vpERROR_TRACE("Unable to choose a good \"out\" level") ;
204  "Unable to choose a good \"out\" level")) ;
205  }
206  gray_level_out = static_cast<unsigned char>(gray_level_max + 1u);
207  }
208 }
209 
227 bool vpDot::connexe(const vpImage<unsigned char>& I,unsigned int u,unsigned int v,
228  double &mean_value, double &u_cog, double &v_cog, double &n)
229 {
230  std::vector<bool> checkTab(I.getWidth()*I.getHeight(),false);
231  return connexe(I,u,v,mean_value,u_cog,v_cog,n,checkTab);
232 }
250 bool vpDot::connexe(const vpImage<unsigned char>& I,unsigned int u,unsigned int v,
251  double &mean_value, double &u_cog, double &v_cog, double &n,std::vector<bool> &checkTab)
252 {
253 
254  unsigned int width = I.getWidth();
255  unsigned int height= I.getHeight();
256 
257  // Test if we are in the image
258  if ( (u >= width) || (v >= height) )
259  {
260  //std::cout << "out of bound" << std::endl;
261  return false;
262  }
263 
264  if(checkTab[u + v*I.getWidth()])
265  return true;
266 
267  vpImagePoint ip;
268  ip.set_u(u);
269  ip.set_v(v);
270 
271  if (I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
272  {
273  checkTab[v*I.getWidth() + u] = true;
274 
275  ip_connexities_list.push_back(ip);
276 
277  u_cog += u ;
278  v_cog += v ;
279  n+=1 ;
280 
281  if (n > nbMaxPoint) {
282  vpERROR_TRACE("Too many point %lf (%lf%% of image size). "
283  "This threshold can be modified using the setMaxDotSize() "
284  "method.",
285  n, n / (I.getWidth() * I.getHeight()),
286  nbMaxPoint, maxDotSizePercentage) ;
287 
289  "Dot to big")) ;
290  }
291 
292  // Bounding box update
293  if (u < this->u_min) this->u_min = u;
294  if (u > this->u_max) this->u_max = u;
295  if (v < this->v_min) this->v_min = v;
296  if (v > this->v_max) this->v_max = v;
297 
298  // Mean value of the dot intensities
299  mean_value = (mean_value *(n-1) + I[v][u]) / n;
300  if (compute_moment==true)
301  {
302  m00++ ;
303  m10 += u ;
304  m01 += v ;
305  m11 += (u*v) ;
306  m20 += u*u ;
307  m02 += v*v ;
308  }
309  }
310  else
311  {
312  //std::cout << "not in" << std::endl;
313  return false;
314  }
315 
316  bool edge = false;
317 
318  //if((int)u-1 >= 0)
319  if(u >= 1)
320  if(!checkTab[u-1 + v*I.getWidth()])
321  if(!connexe(I,u-1,v, mean_value,u_cog,v_cog, n, checkTab))
322  edge = true;
323 
324  if(u+1 < I.getWidth())
325  if(!checkTab[u+1+v*I.getWidth()])
326  if(!connexe(I,u+1,v,mean_value,u_cog, v_cog, n, checkTab))
327  edge = true;
328 
329  if(v >= 1)
330  if(!checkTab[u+(v-1)*I.getWidth()])
331  if(!connexe(I,u, v-1,mean_value,u_cog, v_cog, n, checkTab))
332  edge = true;
333 
334  if(v+1 < I.getHeight())
335  if(!checkTab[u+(v+1)*I.getWidth()])
336  if(!connexe(I,u,v+1,mean_value,u_cog, v_cog, n, checkTab))
337  edge = true;
338 
339  if (connexityType == CONNEXITY_8) {
340  if(v >= 1 && u >= 1)
341  if(!checkTab[u-1+(v-1)*I.getWidth()])
342  if(!connexe(I,u-1,v-1,mean_value,u_cog, v_cog, n, checkTab))
343  edge = true;
344 
345  if(v >= 1 && u+1 < I.getWidth())
346  if(!checkTab[u+1+(v-1)*I.getWidth()])
347  if(!connexe(I,u+1,v-1,mean_value,u_cog, v_cog, n, checkTab))
348  edge = true;
349 
350  if(v+1 < I.getHeight() && u >= 1)
351  if(!checkTab[u-1+(v+1)*I.getWidth()])
352  if(!connexe(I,u-1,v+1,mean_value, u_cog, v_cog, n, checkTab))
353  edge = true;
354 
355  if(v+1 < I.getHeight() && u+1 < I.getWidth())
356  if(!checkTab[u+1+(v+1)*I.getWidth()])
357  if(!connexe(I,u+1,v+1,mean_value,u_cog, v_cog, n, checkTab))
358  edge = true;
359  }
360 
361  if(edge){
362  ip_edges_list.push_back(ip);
363  if (graphics==true)
364  {
365  // printf("u %d v %d\n", u, v);
367  //vpDisplay::flush(I);
368  }
369  }
370 
371  return true;
372 }
373 
393 void
394 vpDot::COG(const vpImage<unsigned char> &I, double& u, double& v)
395 {
396  // Set the maximal number of points considering the maximal dot size
397  // image percentage
398  nbMaxPoint = (I.getWidth() * I.getHeight()) * maxDotSizePercentage;
399 
400  // segmentation de l'image apres seuillage
401  // (etiquetage des composante connexe)
402  if (compute_moment)
403  m00 = m11 = m02 = m20 = m10 = m01 = mu11 = mu20 = mu02 = 0;
404 
405  double u_cog = 0 ;
406  double v_cog = 0 ;
407  double npoint = 0 ;
408  this->mean_gray_level = 0 ;
409 
410  ip_connexities_list.clear() ;
411  ip_edges_list.clear();
412 
413  // Initialise the boundig box
414  this->u_min = I.getWidth();
415  this->u_max = 0;
416  this->v_min = I.getHeight();
417  this->v_max = 0;
418 
419 #if 0
420  // Original version
421  if ( connexe(I, (unsigned int)u, (unsigned int)v,
422  gray_level_min, gray_level_max,
423  mean_gray_level, u_cog, v_cog, npoint) == vpDot::out)
424  {
425  bool sol = false ;
426  unsigned int pas ;
427  for (pas = 2 ; pas <= 25 ; pas ++ )if (sol==false)
428  {
429  for (int k=-1 ; k <=1 ; k++) if (sol==false)
430  for (int l=-1 ; l <=1 ; l++) if (sol==false)
431  {
432  u_cog = 0 ;
433  v_cog = 0 ;
434  ip_connexities_list.clear() ;
435 
436  this->mean_gray_level = 0 ;
437  if (connexe(I, (unsigned int)(u+k*pas),(unsigned int)(v+l*pas),
438  gray_level_min, gray_level_max,
439  mean_gray_level, u_cog, v_cog, npoint) != vpDot::out)
440  {
441  sol = true ; u += k*pas ; v += l*pas ;
442  }
443  }
444  }
445  if (sol == false)
446  {
447  vpERROR_TRACE("Dot has been lost") ;
449  "Dot has been lost")) ;
450  }
451  }
452 #else
453  // If the dot is not found, search around using a spiral
454  if ( !connexe(I,(unsigned int)u,(unsigned int)v, mean_gray_level, u_cog, v_cog, npoint) )
455  {
456  bool sol = false ;
457 
458  unsigned int right = 1;
459  unsigned int botom = 1;
460  unsigned int left = 2;
461  unsigned int up = 2;
462  double u_ = u, v_ = v;
463  unsigned int k;
464 
465  // Spiral search from the center to find the nearest dot
466  while( (right < SPIRAL_SEARCH_SIZE) && (sol == false) ) {
467  for (k=1; k <= right; k++) if(sol==false) {
468  u_cog = 0 ;
469  v_cog = 0 ;
470  ip_connexities_list.clear() ;
471  ip_edges_list.clear();
472 
473  this->mean_gray_level = 0 ;
474  if ( connexe(I, (unsigned int)u_+k, (unsigned int)(v_),mean_gray_level, u_cog, v_cog, npoint) ) {
475  sol = true; u = u_+k; v = v_;
476  }
477  }
478  u_ += k;
479  right += 2;
480 
481  for (k=1; k <= botom; k++) if (sol==false) {
482  u_cog = 0 ;
483  v_cog = 0 ;
484  ip_connexities_list.clear() ;
485  ip_edges_list.clear();
486 
487  this->mean_gray_level = 0 ;
488 
489  if ( connexe(I, (unsigned int)(u_), (unsigned int)(v_+k),mean_gray_level, u_cog, v_cog, npoint) ) {
490  sol = true; u = u_; v = v_+k;
491  }
492  }
493  v_ += k;
494  botom += 2;
495 
496  for (k=1; k <= left; k++) if (sol==false) {
497  u_cog = 0 ;
498  v_cog = 0 ;
499  ip_connexities_list.clear() ;
500  ip_edges_list.clear();
501 
502  this->mean_gray_level = 0 ;
503 
504  if ( connexe(I, (unsigned int)(u_-k), (unsigned int)(v_),mean_gray_level,u_cog, v_cog, npoint) ) {
505  sol = true ; u = u_-k; v = v_;
506  }
507  }
508  u_ -= k;
509  left += 2;
510 
511  for (k=1; k <= up; k++) if(sol==false) {
512  u_cog = 0 ;
513  v_cog = 0 ;
514  ip_connexities_list.clear() ;
515  ip_edges_list.clear();
516 
517  this->mean_gray_level = 0 ;
518 
519  if ( connexe(I, (unsigned int)(u_), (unsigned int)(v_-k),mean_gray_level,u_cog, v_cog, npoint) ) {
520  sol = true ; u = u_; v = v_-k;
521  }
522  }
523  v_ -= k;
524  up += 2;
525  }
526 
527  if (sol == false) {
528  vpERROR_TRACE("Dot has been lost") ;
530  "Dot has been lost")) ;
531  }
532  }
533 
534 #endif
535 /*
536  vpImagePoint ip;
537  unsigned int i, j;
538  std::list<vpImagePoint>::iterator it;
539  for (it = ip_connexities_list.begin(); it != ip_connexities_list.end(); it ++) {
540  ip = *it;
541  i = (unsigned int) ip.get_i();
542  j = (unsigned int) ip.get_j();
543  I[i][j] = 255 ;
544  }*/
545 
546  u_cog = u_cog/npoint ;
547  v_cog = v_cog/npoint ;
548 
549  u = u_cog ;
550  v = v_cog ;
551 
552  // Initialize the threshold for the next call to track()
553  double Ip = pow((double)this->mean_gray_level/255,1/gamma);
554 
555  if(Ip - (1 - grayLevelPrecision)<0){
556  gray_level_min = 0 ;
557  }
558  else{
559  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
560  if (gray_level_min > 255)
561  gray_level_min = 255;
562  }
563  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
564  if (gray_level_max > 255)
565  gray_level_max = 255;
566 
567  //vpCTRACE << "gray_level_min: " << gray_level_min << std::endl;
568  //vpCTRACE << "gray_level_max: " << gray_level_max << std::endl;
569 
570  if (npoint < 5)
571  {
572  vpERROR_TRACE("Dot to small") ;
574  "Dot to small")) ;
575  }
576 
577  if (npoint > nbMaxPoint)
578  {
579  vpERROR_TRACE("Too many point %lf (%lf%%). Max allowed is %lf (%lf%%). This threshold can be modified using the setMaxDotSize() method.",
580  npoint, npoint / (I.getWidth() * I.getHeight()),
581  nbMaxPoint, maxDotSizePercentage) ;
582 
584  "Dot to big")) ;
585  }
586 }
587 
600 void
601 vpDot::setMaxDotSize(double percentage)
602 {
603  if (percentage <= 0.0 || percentage > 1.0) {
604  // print a warning. We keep the default percentage
605  vpTRACE("Max dot size percentage is requested to be set to %lf.",
606  "Value should be in ]0:1]. Value will be set to %lf.",
607  percentage, maxDotSizePercentage);
608  }
609  else {
610  maxDotSizePercentage = percentage;
611  }
612 }
613 
637 void
639 {
640  while (vpDisplay::getClick(I, cog) != true) ;
641 
642  unsigned int i = (unsigned int)cog.get_i();
643  unsigned int j = (unsigned int)cog.get_j();
644 
645  double Ip = pow((double)I[i][j]/255, 1/gamma);
646 
647  if(Ip - (1 - grayLevelPrecision)<0){
648  gray_level_min = 0 ;
649  }
650  else{
651  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
652  if (gray_level_min > 255)
653  gray_level_min = 255;
654  }
655  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
656  if (gray_level_max > 255)
657  gray_level_max = 255;
658 
659  try {
660  track( I );
661  }
662  catch(...)
663  {
664  vpERROR_TRACE("Error caught") ;
665  throw ;
666  }
667 }
668 
692 void
694 {
695 
696  cog = ip ;
697 
698  unsigned int i = (unsigned int)cog.get_i();
699  unsigned int j = (unsigned int)cog.get_j();
700 
701  double Ip = pow((double)I[i][j]/255, 1/gamma);
702 
703  if(Ip - (1 - grayLevelPrecision)<0){
704  gray_level_min = 0 ;
705  }
706  else{
707  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
708  if (gray_level_min > 255)
709  gray_level_min = 255;
710  }
711  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
712  if (gray_level_max > 255)
713  gray_level_max = 255;
714  try {
715  track( I );
716  }
717  catch(...)
718  {
719  vpERROR_TRACE("Error caught") ;
720  throw ;
721  }
722 }
723 
751 void
753  unsigned int gray_level_min, unsigned int gray_level_max)
754 {
755 
756  cog = ip ;
757 
758  this->gray_level_min = gray_level_min;
759  this->gray_level_max = gray_level_max;
760 
761  try {
762  track( I );
763  }
764  catch(...)
765  {
766  vpERROR_TRACE("Error caught") ;
767  throw ;
768  }
769 }
770 
771 
786 void
788 {
789  try{
790  setGrayLevelOut();
791  double u = this->cog.get_u();
792  double v = this->cog.get_v();
793 
794  COG( I, u, v ) ;
795 
796  this->cog.set_u( u );
797  this->cog.set_v( v );
798 
799  if (compute_moment==true)
800  {
801  mu11 = m11 - u*m01;
802  mu02 = m02 - v*m01;
803  mu20 = m20 - u*m10;
804  }
805  }
806  catch(...)
807  {
808  vpERROR_TRACE("Error caught") ;
809  throw ;
810  }
811 }
812 
827 void
829 {
830  track( I ) ;
831 
832  cog = this->cog;
833 }
834 
843  unsigned int thickness)
844 {
845  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
846  std::list<vpImagePoint>::const_iterator it;
847 
848  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it)
849  {
850  vpDisplay::displayPoint(I, *it, color);
851  }
852 }
853 
871 void vpDot::setGrayLevelPrecision( const double & grayLevelPrecision )
872 {
873  double epsilon = 0.05;
874  if( grayLevelPrecision<epsilon )
875  {
876  this->grayLevelPrecision = epsilon;
877  }
878  else if( grayLevelPrecision>1 )
879  {
880  this->grayLevelPrecision = 1.0;
881  }
882  else
883  {
884  this->grayLevelPrecision = grayLevelPrecision;
885  }
886 }
887 
903  const std::list<vpImagePoint> &edges_list, vpColor color,
904  unsigned int thickness)
905 {
906  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
907  std::list<vpImagePoint>::const_iterator it;
908 
909  for (it = edges_list.begin(); it != edges_list.end(); ++it)
910  {
911  vpDisplay::displayPoint(I, *it, color);
912  }
913 }
914 
915 
916 /*
917  * Local variables:
918  * c-basic-offset: 2
919  * End:
920  */
921 
922 
double get_v() const
Definition: vpImagePoint.h:250
double mu20
Definition: vpDot.h:148
bool operator!=(const vpDot &d)
Definition: vpDot.cpp:174
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
Definition: vpDot.cpp:842
void setMaxDotSize(double percentage)
Definition: vpDot.cpp:601
double get_i() const
Definition: vpImagePoint.h:181
unsigned int getWidth() const
Definition: vpImage.h:154
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot.cpp:871
double m10
Definition: vpDot.h:109
#define vpERROR_TRACE
Definition: vpDebug.h:379
#define vpTRACE
Definition: vpDebug.h:401
Class to define colors available for display functionnalities.
Definition: vpColor.h:123
double get_u() const
Definition: vpImagePoint.h:239
void track(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:787
double m00
Definition: vpDot.h:95
double mu11
Definition: vpDot.h:143
double mu02
Definition: vpDot.h:153
double get_j() const
Definition: vpImagePoint.h:192
static const unsigned int SPIRAL_SEARCH_SIZE
Definition: vpDot.h:93
double m20
Definition: vpDot.h:125
double m11
Definition: vpDot.h:116
static const vpColor red
Definition: vpColor.h:165
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:69
vpImagePoint getCog() const
Definition: vpDot.h:249
double m01
Definition: vpDot.h:102
Error that can be emited by the vpTracker class and its derivates.
vpDot & operator=(const vpDot &d)
Copy operator.
Definition: vpDot.cpp:138
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:134
vpDot()
Definition: vpDot.cpp:97
This tracker is meant to track a dot (connex pixels with same gray level) on a vpImage.
Definition: vpDot.h:80
unsigned int getHeight() const
Definition: vpImage.h:145
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:180
void initTracking(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:638
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
virtual ~vpDot()
Destructor.
Definition: vpDot.cpp:128