ViSP  2.7.0
vpDot.cpp
1 /****************************************************************************
2  *
3  * $Id: vpDot.cpp 4092 2013-02-04 10:36:30Z 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  cog = d.getCog();
139 
140  graphics = d.graphics ;
141  thickness = d.thickness;
142  mean_gray_level = d.mean_gray_level ;
143  gray_level_min = d.gray_level_min ;
144  gray_level_max = d.gray_level_max ;
145  grayLevelPrecision = d.grayLevelPrecision;
146  compute_moment = d.compute_moment ;
147 
148  maxDotSizePercentage = d.maxDotSizePercentage;
149 
150  m00 = d.m00;
151  m01 = d.m01;
152  m10 = d.m10;
153  m02 = d.m02;
154  m20 = d.m20;
155  mu11 = d.mu11;
156  mu20 = d.mu20;
157  mu02 = d.mu02;
158 
159  u_min = d.u_min;
160  v_min = d.v_min;
161  u_max = d.u_max;
162  v_max = d.v_max;
163 
164  gray_level_out = d.gray_level_out;
165  gamma = d.gamma;
166 
167  nbMaxPoint = d.nbMaxPoint;
168 
169  return *this ;
170 }
171 
172 bool
174 {
175  return ( cog != d.getCog() );
176 }
177 
178 bool
180 {
181  return ( cog == d.getCog() );
182 }
183 
195 void
196 vpDot::setGrayLevelOut()
197 {
198  if (gray_level_min == 0) {
199  if (gray_level_max == 255) {
200  // gray_level_min = 0 and gray_level_max = 255: this should not occur
201  vpERROR_TRACE("Unable to choose a good \"out\" level") ;
203  "Unable to choose a good \"out\" level")) ;
204  }
205  gray_level_out = static_cast<unsigned char>(gray_level_max + 1u);
206  }
207 }
208 
226 bool vpDot::connexe(const vpImage<unsigned char>& I,unsigned int u,unsigned int v,
227  double &mean_value, double &u_cog, double &v_cog, double &n)
228 {
229  std::vector<bool> checkTab(I.getWidth()*I.getHeight(),false);
230  return connexe(I,u,v,mean_value,u_cog,v_cog,n,checkTab);
231 }
249 bool vpDot::connexe(const vpImage<unsigned char>& I,unsigned int u,unsigned int v,
250  double &mean_value, double &u_cog, double &v_cog, double &n,std::vector<bool> &checkTab)
251 {
252 
253  unsigned int width = I.getWidth();
254  unsigned int height= I.getHeight();
255 
256  // Test if we are in the image
257  if ( (u >= width) || (v >= height) )
258  {
259  //std::cout << "out of bound" << std::endl;
260  return false;
261  }
262 
263  if(checkTab[u + v*I.getWidth()])
264  return true;
265 
266  vpImagePoint ip;
267  ip.set_u(u);
268  ip.set_v(v);
269 
270  if (I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
271  {
272  checkTab[v*I.getWidth() + u] = true;
273 
274  ip_connexities_list.push_back(ip);
275 
276  u_cog += u ;
277  v_cog += v ;
278  n+=1 ;
279 
280  if (n > nbMaxPoint) {
281  vpERROR_TRACE("Too many point %lf (%lf%% of image size). "
282  "This threshold can be modified using the setMaxDotSize() "
283  "method.",
284  n, n / (I.getWidth() * I.getHeight()),
285  nbMaxPoint, maxDotSizePercentage) ;
286 
288  "Dot to big")) ;
289  }
290 
291  // Bounding box update
292  if (u < this->u_min) this->u_min = u;
293  if (u > this->u_max) this->u_max = u;
294  if (v < this->v_min) this->v_min = v;
295  if (v > this->v_max) this->v_max = v;
296 
297  // Mean value of the dot intensities
298  mean_value = (mean_value *(n-1) + I[v][u]) / n;
299  if (compute_moment==true)
300  {
301  m00++ ;
302  m10 += u ;
303  m01 += v ;
304  m11 += (u*v) ;
305  m20 += u*u ;
306  m02 += v*v ;
307  }
308  }
309  else
310  {
311  //std::cout << "not in" << std::endl;
312  return false;
313  }
314 
315  bool edge = false;
316 
317  //if((int)u-1 >= 0)
318  if(u >= 1)
319  if(!checkTab[u-1 + v*I.getWidth()])
320  if(!connexe(I,u-1,v, mean_value,u_cog,v_cog, n, checkTab))
321  edge = true;
322 
323  if(u+1 < I.getWidth())
324  if(!checkTab[u+1+v*I.getWidth()])
325  if(!connexe(I,u+1,v,mean_value,u_cog, v_cog, n, checkTab))
326  edge = true;
327 
328  if(v >= 1)
329  if(!checkTab[u+(v-1)*I.getWidth()])
330  if(!connexe(I,u, v-1,mean_value,u_cog, v_cog, n, checkTab))
331  edge = true;
332 
333  if(v+1 < I.getHeight())
334  if(!checkTab[u+(v+1)*I.getWidth()])
335  if(!connexe(I,u,v+1,mean_value,u_cog, v_cog, n, checkTab))
336  edge = true;
337 
338  if (connexityType == CONNEXITY_8) {
339  if(v >= 1 && u >= 1)
340  if(!checkTab[u-1+(v-1)*I.getWidth()])
341  if(!connexe(I,u-1,v-1,mean_value,u_cog, v_cog, n, checkTab))
342  edge = true;
343 
344  if(v >= 1 && u+1 < I.getWidth())
345  if(!checkTab[u+1+(v-1)*I.getWidth()])
346  if(!connexe(I,u+1,v-1,mean_value,u_cog, v_cog, n, checkTab))
347  edge = true;
348 
349  if(v+1 < I.getHeight() && u >= 1)
350  if(!checkTab[u-1+(v+1)*I.getWidth()])
351  if(!connexe(I,u-1,v+1,mean_value, u_cog, v_cog, n, checkTab))
352  edge = true;
353 
354  if(v+1 < I.getHeight() && u+1 < I.getWidth())
355  if(!checkTab[u+1+(v+1)*I.getWidth()])
356  if(!connexe(I,u+1,v+1,mean_value,u_cog, v_cog, n, checkTab))
357  edge = true;
358  }
359 
360  if(edge){
361  ip_edges_list.push_back(ip);
362  if (graphics==true)
363  {
364  vpImagePoint ip_(ip);
365  for(unsigned int t=0; t<thickness; t++) {
366  ip_.set_u(ip.get_u() + t);
368  }
369  //vpDisplay::flush(I);
370  }
371  }
372 
373  return true;
374 }
375 
395 void
396 vpDot::COG(const vpImage<unsigned char> &I, double& u, double& v)
397 {
398  // Set the maximal number of points considering the maximal dot size
399  // image percentage
400  nbMaxPoint = (I.getWidth() * I.getHeight()) * maxDotSizePercentage;
401 
402  // segmentation de l'image apres seuillage
403  // (etiquetage des composante connexe)
404  if (compute_moment)
405  m00 = m11 = m02 = m20 = m10 = m01 = mu11 = mu20 = mu02 = 0;
406 
407  double u_cog = 0 ;
408  double v_cog = 0 ;
409  double npoint = 0 ;
410  this->mean_gray_level = 0 ;
411 
412  ip_connexities_list.clear() ;
413  ip_edges_list.clear();
414 
415  // Initialise the boundig box
416  this->u_min = I.getWidth();
417  this->u_max = 0;
418  this->v_min = I.getHeight();
419  this->v_max = 0;
420 
421 #if 0
422  // Original version
423  if ( connexe(I, (unsigned int)u, (unsigned int)v,
424  gray_level_min, gray_level_max,
425  mean_gray_level, u_cog, v_cog, npoint) == vpDot::out)
426  {
427  bool sol = false ;
428  unsigned int pas ;
429  for (pas = 2 ; pas <= 25 ; pas ++ )if (sol==false)
430  {
431  for (int k=-1 ; k <=1 ; k++) if (sol==false)
432  for (int l=-1 ; l <=1 ; l++) if (sol==false)
433  {
434  u_cog = 0 ;
435  v_cog = 0 ;
436  ip_connexities_list.clear() ;
437 
438  this->mean_gray_level = 0 ;
439  if (connexe(I, (unsigned int)(u+k*pas),(unsigned int)(v+l*pas),
440  gray_level_min, gray_level_max,
441  mean_gray_level, u_cog, v_cog, npoint) != vpDot::out)
442  {
443  sol = true ; u += k*pas ; v += l*pas ;
444  }
445  }
446  }
447  if (sol == false)
448  {
449  vpERROR_TRACE("Dot has been lost") ;
451  "Dot has been lost")) ;
452  }
453  }
454 #else
455  // If the dot is not found, search around using a spiral
456  if ( !connexe(I,(unsigned int)u,(unsigned int)v, mean_gray_level, u_cog, v_cog, npoint) )
457  {
458  bool sol = false ;
459 
460  unsigned int right = 1;
461  unsigned int botom = 1;
462  unsigned int left = 2;
463  unsigned int up = 2;
464  double u_ = u, v_ = v;
465  unsigned int k;
466 
467  // Spiral search from the center to find the nearest dot
468  while( (right < SPIRAL_SEARCH_SIZE) && (sol == false) ) {
469  for (k=1; k <= right; k++) if(sol==false) {
470  u_cog = 0 ;
471  v_cog = 0 ;
472  ip_connexities_list.clear() ;
473  ip_edges_list.clear();
474 
475  this->mean_gray_level = 0 ;
476  if ( connexe(I, (unsigned int)u_+k, (unsigned int)(v_),mean_gray_level, u_cog, v_cog, npoint) ) {
477  sol = true; u = u_+k; v = v_;
478  }
479  }
480  u_ += k;
481  right += 2;
482 
483  for (k=1; k <= botom; k++) if (sol==false) {
484  u_cog = 0 ;
485  v_cog = 0 ;
486  ip_connexities_list.clear() ;
487  ip_edges_list.clear();
488 
489  this->mean_gray_level = 0 ;
490 
491  if ( connexe(I, (unsigned int)(u_), (unsigned int)(v_+k),mean_gray_level, u_cog, v_cog, npoint) ) {
492  sol = true; u = u_; v = v_+k;
493  }
494  }
495  v_ += k;
496  botom += 2;
497 
498  for (k=1; k <= left; k++) if (sol==false) {
499  u_cog = 0 ;
500  v_cog = 0 ;
501  ip_connexities_list.clear() ;
502  ip_edges_list.clear();
503 
504  this->mean_gray_level = 0 ;
505 
506  if ( connexe(I, (unsigned int)(u_-k), (unsigned int)(v_),mean_gray_level,u_cog, v_cog, npoint) ) {
507  sol = true ; u = u_-k; v = v_;
508  }
509  }
510  u_ -= k;
511  left += 2;
512 
513  for (k=1; k <= up; k++) if(sol==false) {
514  u_cog = 0 ;
515  v_cog = 0 ;
516  ip_connexities_list.clear() ;
517  ip_edges_list.clear();
518 
519  this->mean_gray_level = 0 ;
520 
521  if ( connexe(I, (unsigned int)(u_), (unsigned int)(v_-k),mean_gray_level,u_cog, v_cog, npoint) ) {
522  sol = true ; u = u_; v = v_-k;
523  }
524  }
525  v_ -= k;
526  up += 2;
527  }
528 
529  if (sol == false) {
530  vpERROR_TRACE("Dot has been lost") ;
532  "Dot has been lost")) ;
533  }
534  }
535 
536 #endif
537 /*
538  vpImagePoint ip;
539  unsigned int i, j;
540  std::list<vpImagePoint>::iterator it;
541  for (it = ip_connexities_list.begin(); it != ip_connexities_list.end(); it ++) {
542  ip = *it;
543  i = (unsigned int) ip.get_i();
544  j = (unsigned int) ip.get_j();
545  I[i][j] = 255 ;
546  }*/
547 
548  u_cog = u_cog/npoint ;
549  v_cog = v_cog/npoint ;
550 
551  u = u_cog ;
552  v = v_cog ;
553 
554  // Initialize the threshold for the next call to track()
555  double Ip = pow((double)this->mean_gray_level/255,1/gamma);
556 
557  if(Ip - (1 - grayLevelPrecision)<0){
558  gray_level_min = 0 ;
559  }
560  else{
561  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
562  if (gray_level_min > 255)
563  gray_level_min = 255;
564  }
565  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
566  if (gray_level_max > 255)
567  gray_level_max = 255;
568 
569  //vpCTRACE << "gray_level_min: " << gray_level_min << std::endl;
570  //vpCTRACE << "gray_level_max: " << gray_level_max << std::endl;
571 
572  if (npoint < 5)
573  {
574  vpERROR_TRACE("Dot to small") ;
576  "Dot to small")) ;
577  }
578 
579  if (npoint > nbMaxPoint)
580  {
581  vpERROR_TRACE("Too many point %lf (%lf%%). Max allowed is %lf (%lf%%). This threshold can be modified using the setMaxDotSize() method.",
582  npoint, npoint / (I.getWidth() * I.getHeight()),
583  nbMaxPoint, maxDotSizePercentage) ;
584 
586  "Dot to big")) ;
587  }
588 }
589 
602 void
603 vpDot::setMaxDotSize(double percentage)
604 {
605  if (percentage <= 0.0 || percentage > 1.0) {
606  // print a warning. We keep the default percentage
607  vpTRACE("Max dot size percentage is requested to be set to %lf.",
608  "Value should be in ]0:1]. Value will be set to %lf.",
609  percentage, maxDotSizePercentage);
610  }
611  else {
612  maxDotSizePercentage = percentage;
613  }
614 }
615 
639 void
641 {
642  while (vpDisplay::getClick(I, cog) != true) ;
643 
644  unsigned int i = (unsigned int)cog.get_i();
645  unsigned int j = (unsigned int)cog.get_j();
646 
647  double Ip = pow((double)I[i][j]/255, 1/gamma);
648 
649  if(Ip - (1 - grayLevelPrecision)<0){
650  gray_level_min = 0 ;
651  }
652  else{
653  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
654  if (gray_level_min > 255)
655  gray_level_min = 255;
656  }
657  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
658  if (gray_level_max > 255)
659  gray_level_max = 255;
660 
661  try {
662  track( I );
663  }
664  catch(...)
665  {
666  vpERROR_TRACE("Error caught") ;
667  throw ;
668  }
669 }
670 
694 void
696 {
697 
698  cog = ip ;
699 
700  unsigned int i = (unsigned int)cog.get_i();
701  unsigned int j = (unsigned int)cog.get_j();
702 
703  double Ip = pow((double)I[i][j]/255, 1/gamma);
704 
705  if(Ip - (1 - grayLevelPrecision)<0){
706  gray_level_min = 0 ;
707  }
708  else{
709  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
710  if (gray_level_min > 255)
711  gray_level_min = 255;
712  }
713  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
714  if (gray_level_max > 255)
715  gray_level_max = 255;
716  try {
717  track( I );
718  }
719  catch(...)
720  {
721  vpERROR_TRACE("Error caught") ;
722  throw ;
723  }
724 }
725 
753 void
755  unsigned int gray_level_min, unsigned int gray_level_max)
756 {
757 
758  cog = ip ;
759 
760  this->gray_level_min = gray_level_min;
761  this->gray_level_max = gray_level_max;
762 
763  try {
764  track( I );
765  }
766  catch(...)
767  {
768  vpERROR_TRACE("Error caught") ;
769  throw ;
770  }
771 }
772 
773 
788 void
790 {
791  try{
792  setGrayLevelOut();
793  double u = this->cog.get_u();
794  double v = this->cog.get_v();
795 
796  COG( I, u, v ) ;
797 
798  this->cog.set_u( u );
799  this->cog.set_v( v );
800 
801  if (compute_moment==true)
802  {
803  mu11 = m11 - u*m01;
804  mu02 = m02 - v*m01;
805  mu20 = m20 - u*m10;
806  }
807 
808  if (graphics) {
809  // display a red cross at the center of gravity's location in the image.
810  vpDisplay::displayCross(I, this->cog, 3*thickness+8, vpColor::red, thickness);
811  }
812 
813  }
814  catch(...)
815  {
816  vpERROR_TRACE("Error caught") ;
817  throw ;
818  }
819 }
820 
835 void
837 {
838  track( I ) ;
839 
840  cog = this->cog;
841 }
842 
851  unsigned int thickness)
852 {
853  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
854  std::list<vpImagePoint>::const_iterator it;
855 
856  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it)
857  {
858  vpDisplay::displayPoint(I, *it, color);
859  }
860 }
861 
879 void vpDot::setGrayLevelPrecision( const double & grayLevelPrecision )
880 {
881  double epsilon = 0.05;
882  if( grayLevelPrecision<epsilon )
883  {
884  this->grayLevelPrecision = epsilon;
885  }
886  else if( grayLevelPrecision>1 )
887  {
888  this->grayLevelPrecision = 1.0;
889  }
890  else
891  {
892  this->grayLevelPrecision = grayLevelPrecision;
893  }
894 }
895 
911  const std::list<vpImagePoint> &edges_list, vpColor color,
912  unsigned int thickness)
913 {
914  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
915  std::list<vpImagePoint>::const_iterator it;
916 
917  for (it = edges_list.begin(); it != edges_list.end(); ++it)
918  {
919  vpDisplay::displayPoint(I, *it, color);
920  }
921 }
922 
937 void vpDot::display(const vpImage<vpRGBa>& I,const vpImagePoint &cog,
938  const std::list<vpImagePoint> &edges_list, vpColor color,
939  unsigned int thickness)
940 {
941  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
942  std::list<vpImagePoint>::const_iterator it;
943 
944  for (it = edges_list.begin(); it != edges_list.end(); ++it)
945  {
946  vpDisplay::displayPoint(I, *it, color);
947  }
948 }
949 
950 
951 
double get_v() const
Definition: vpImagePoint.h:250
double mu20
Definition: vpDot.h:184
bool operator!=(const vpDot &d)
Definition: vpDot.cpp:173
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
Definition: vpDot.cpp:850
void setMaxDotSize(double percentage)
Definition: vpDot.cpp:603
double get_i() const
Definition: vpImagePoint.h:181
unsigned int getWidth() const
Definition: vpImage.h:154
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot.cpp:879
double m10
Definition: vpDot.h:145
#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:789
double m00
Definition: vpDot.h:131
double mu11
Definition: vpDot.h:179
double mu02
Definition: vpDot.h:189
double get_j() const
Definition: vpImagePoint.h:192
static const unsigned int SPIRAL_SEARCH_SIZE
Definition: vpDot.h:129
double m20
Definition: vpDot.h:161
double m11
Definition: vpDot.h:152
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:225
double m01
Definition: vpDot.h:138
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:170
vpDot()
Definition: vpDot.cpp:98
This tracker is meant to track a dot (connex pixels with same gray level) on a vpImage.
Definition: vpDot.h:116
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:179
void initTracking(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:640
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
virtual ~vpDot()
Destructor.
Definition: vpDot.cpp:126