ViSP  2.9.0
vpDot2.cpp
1 /****************************************************************************
2  *
3  * $Id: vpDot2.cpp 2135 2009-04-29 13:51:31Z 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  * Track a white dot.
36  *
37  * Authors:
38  * Fabien Spindler
39  * Anthony Saunier
40  *
41  *****************************************************************************/
42 
48 //#define DEBUG
49 
50 
51 #include <visp/vpDisplay.h>
52 
53 // exception handling
54 #include <visp/vpTrackingException.h>
55 #include <visp/vpMath.h>
56 #include <visp/vpIoTools.h>
57 
58 #include <visp/vpDot2.h>
59 #include <math.h>
60 #include <iostream>
61 #include <cmath> // std::fabs
62 #include <limits> // numeric_limits
63 
64 /******************************************************************************
65  *
66  * CONSTRUCTORS AND DESTRUCTORS
67  *
68  *****************************************************************************/
74 void vpDot2::init()
75 {
76  cog.set_u(0);
77  cog.set_v(0);
78 
79  width = 0;
80  height = 0;
81  surface = 0;
82  mean_gray_level = 0;
83  gray_level_min = 128;
84  gray_level_max = 255;
85  grayLevelPrecision = 0.80;
86  gamma = 1.5 ;
87 
88  sizePrecision = 0.65;
89  ellipsoidShapePrecision = 0.65;
90  maxSizeSearchDistancePrecision = 0.65;
92  m00 = m11 = m02 = m20 = m10 = m01 = 0.;
93  mu11 = mu02 = mu20 = 0.;
94 
95  bbox_u_min = bbox_u_max = bbox_v_min = bbox_v_max = 0;
96 
97  firstBorder_u = 0;
98  firstBorder_v = 0;
99 
100  compute_moment = false ;
101  graphics = false;
102  thickness = 1;
103 }
104 
109  : m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.),
110  mu11(0.), mu20(0.), mu02(0.), cog(), width(0), height(0), surface(0),
111  gray_level_min(128), gray_level_max(255), mean_gray_level(0), grayLevelPrecision(0.8), gamma(1.5),
112  sizePrecision(0.65), ellipsoidShapePrecision(0.65), maxSizeSearchDistancePrecision(0.65),
113  allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(), compute_moment(false),
114  graphics(false), thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0),
115  firstBorder_u(0), firstBorder_v()
116 {
117 }
118 
128  : m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.),
129  mu11(0.), mu20(0.), mu02(0.), cog(), width(0), height(0), surface(0),
130  gray_level_min(128), gray_level_max(255), mean_gray_level(0), grayLevelPrecision(0.8), gamma(1.5),
131  sizePrecision(0.65), ellipsoidShapePrecision(0.65), maxSizeSearchDistancePrecision(0.65),
132  allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(), compute_moment(false),
133  graphics(false), thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0),
134  firstBorder_u(0), firstBorder_v()
135 {
136  cog = ip;
137 }
138 
142 vpDot2::vpDot2(const vpDot2& twinDot )
143  : vpTracker(twinDot),
144  m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.),
145  mu11(0.), mu20(0.), mu02(0.), cog(), width(0), height(0), surface(0),
146  gray_level_min(128), gray_level_max(255), mean_gray_level(0), grayLevelPrecision(0.8), gamma(1.5),
147  sizePrecision(0.65), ellipsoidShapePrecision(0.65), maxSizeSearchDistancePrecision(0.65),
148  allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(), compute_moment(false),
149  graphics(false), thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0),
150  firstBorder_u(0), firstBorder_v()
151 {
152  *this = twinDot;
153 }
154 
158 vpDot2& vpDot2::operator=(const vpDot2& twinDot )
159 {
160  cog = twinDot.cog;
161 
162  width = twinDot.width;
163  height = twinDot.height;
164  surface = twinDot.surface;
165  gray_level_min = twinDot.gray_level_min;
166  gray_level_max = twinDot.gray_level_max;
167  mean_gray_level = twinDot.mean_gray_level;
168  grayLevelPrecision = twinDot.grayLevelPrecision;
169  gamma = twinDot.gamma; ;
170  sizePrecision = twinDot.sizePrecision;
171  ellipsoidShapePrecision = twinDot.ellipsoidShapePrecision ;
172  maxSizeSearchDistancePrecision = twinDot.maxSizeSearchDistancePrecision;
173  allowedBadPointsPercentage_ = twinDot.allowedBadPointsPercentage_;
174  area = twinDot.area;
175 
176  direction_list = twinDot.direction_list;
177  ip_edges_list = twinDot.ip_edges_list;
178 
179  compute_moment = twinDot.compute_moment;
180  graphics = twinDot.graphics;
181  thickness = twinDot.thickness;
182 
183  bbox_u_min = twinDot.bbox_u_min;
184  bbox_u_max = twinDot.bbox_u_max;
185  bbox_v_min = twinDot.bbox_v_min;
186  bbox_v_max = twinDot.bbox_v_max;
187 
188  firstBorder_u = twinDot.firstBorder_u;
189  firstBorder_v = twinDot.firstBorder_v;
190 
191  m00 = twinDot.m00;
192  m01 = twinDot.m01;
193  m11 = twinDot.m11;
194  m10 = twinDot.m10;
195  m02 = twinDot.m02;
196  m20 = twinDot.m20;
197 
198  mu11 = twinDot.mu11;
199  mu20 = twinDot.mu20;
200  mu02 = twinDot.mu02;
201 
202  return (*this);
203 }
204 
209 
210 
211 /******************************************************************************
212  *
213  * PUBLIC METHODS
214  *****************************************************************************/
215 
223 void vpDot2::display(const vpImage<unsigned char>& I, vpColor color, unsigned int t) const
224 {
225  vpDisplay::displayCross(I, cog, 3*t+8, color, t);
226  std::list<vpImagePoint>::const_iterator it;
227 
228  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it)
229  {
230  vpDisplay::displayPoint(I, *it, color);
231  }
232 }
233 
234 
266 void vpDot2::initTracking(const vpImage<unsigned char>& I, unsigned int size)
267 {
268  while ( vpDisplay::getClick(I, cog) != true) ;
269 
270  unsigned int i = (unsigned int)cog.get_i();
271  unsigned int j = (unsigned int)cog.get_j();
272 
273  double Ip = pow((double)I[i][j]/255,1/gamma);
274 
275  if(Ip - (1 - grayLevelPrecision)<0){
276  gray_level_min = 0 ;
277  }
278  else{
279  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
280  if (gray_level_min > 255)
281  gray_level_min = 255;
282  }
283  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
284  if (gray_level_max > 255)
285  gray_level_max = 255;
286 
287  setWidth(size);
288  setHeight(size);
289 
290  try {
291  track( I );
292  }
293  catch(...)
294  {
295  vpERROR_TRACE("Error caught") ;
296  throw ;
297  }
298 }
299 
328  const vpImagePoint &ip, unsigned int size)
329 {
330  cog = ip ;
331 
332  unsigned int i = (unsigned int)cog.get_i();
333  unsigned int j = (unsigned int)cog.get_j();
334 
335  double Ip = pow((double)I[i][j]/255,1/gamma);
336 
337  if(Ip - (1 - grayLevelPrecision)<0){
338  gray_level_min = 0 ;
339  }
340  else{
341  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
342  if (gray_level_min > 255)
343  gray_level_min = 255;
344  }
345  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
346  if (gray_level_max > 255)
347  gray_level_max = 255;
348 
349  setWidth(size);
350  setHeight(size);
351 
352  try {
353  track( I );
354  }
355  catch(...)
356  {
357  vpERROR_TRACE("Error caught") ;
358  throw ;
359  }
360 }
361 
402  const vpImagePoint &ip,
403  unsigned int gray_lvl_min,
404  unsigned int gray_lvl_max,
405  unsigned int size)
406 {
407  cog = ip ;
408 
409  this->gray_level_min = gray_lvl_min;
410  this->gray_level_max = gray_lvl_max;
411 
412  setWidth(size);
413  setHeight(size);
414 
415  try {
416  track( I );
417  }
418  catch(...)
419  {
420  vpERROR_TRACE("Error caught") ;
421  throw ;
422  }
423 }
424 
425 
426 
466 {
467  m00 = m11 = m02 = m20 = m10 = m01 = 0 ;
468 
469  // First, we will estimate the position of the tracked point
470 
471  // Set the search area to the entire image
472  setArea(I);
473 
474  // create a copy of the dot to search
475  // This copy can be saw as the previous dot used to check if the current one
476  // found with computeParameters() is similar to the previous one (see isValid()
477  // function).
478  // If the found dot is not similar (or valid), we use this copy to set the current
479  // found dot to the previous one (see below).
480  vpDot2 wantedDot(*this);
481 
482  // vpDEBUG_TRACE(0, "Previous dot: ");
483  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
484  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
485  bool found = false;
486  found = computeParameters(I, cog.get_u(), cog.get_v());
487 
488  if (found) {
489  // test if the found dot is valid (ie similar to the previous one)
490  found = isValid( I, wantedDot);
491  if (! found) {
492  *this = wantedDot;
493  //std::cout << "The found dot is not valid" << std::endl;
494  }
495  }
496 
497  if (! found) {
498  // vpDEBUG_TRACE(0, "Search the dot in a biggest window around the last position");
499  // vpDEBUG_TRACE(0, "Bad computed dot: ");
500  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
501  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
502 
503  // if estimation was wrong (get an error tracking), look for the dot
504  // closest from the estimation,
505  // i.e. search for dots in an a region of interest around the this dot and get the first
506  // element in the area.
507 
508  // first get the size of the search window from the dot size
509  double searchWindowWidth, searchWindowHeight;
510  //if( getWidth() == 0 || getHeight() == 0 )
511  if( std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() || std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon() )
512  {
513  searchWindowWidth = 80.;
514  searchWindowHeight = 80.;
515  }
516  else
517  {
518  searchWindowWidth = getWidth() * 5;
519  searchWindowHeight = getHeight() * 5;
520  }
521  std::list<vpDot2> candidates;
522  searchDotsInArea( I,
523  (int)(this->cog.get_u()-searchWindowWidth /2.0),
524  (int)(this->cog.get_v()-searchWindowHeight/2.0),
525  (unsigned int)searchWindowWidth,
526  (unsigned int)searchWindowHeight,
527  candidates);
528 
529  // if the vector is empty, that mean we didn't find any candidate
530  // in the area, return an error tracking.
531  if( candidates.empty() )
532  {
533  vpERROR_TRACE("No dot was found") ;
535  "No dot was found")) ;
536  }
537 
538  // otherwise we've got our dot, update this dot's parameters
539  vpDot2 movingDot = candidates.front();
540 
541  setCog( movingDot.getCog() );
542  setArea( movingDot.getArea() );
543  setWidth( movingDot.getWidth() );
544  setHeight( movingDot.getHeight() );
545 
546  // Update the moments
547  m00 = movingDot.m00;
548  m01 = movingDot.m01;
549  m10 = movingDot.m10;
550  m11 = movingDot.m11;
551  m20 = movingDot.m20;
552  m02 = movingDot.m02;
553 
554  // Update the bounding box
555  bbox_u_min = movingDot.bbox_u_min;
556  bbox_u_max = movingDot.bbox_u_max;
557  bbox_v_min = movingDot.bbox_v_min;
558  bbox_v_max = movingDot.bbox_v_max;
559  }
560  // else {
561  // // test if the found dot is valid,
562  // if( ! isValid( I, wantedDot ) ) {
563  // *this = wantedDot;
564  // vpERROR_TRACE("The found dot is invalid:",
565  // "- could be a problem of size (width or height) or "
566  // " surface (number of pixels) which differ too much "
567  // " to the previous one "
568  // "- or a problem of the shape which is not ellipsoid if "
569  // " use setEllipsoidShapePrecision(double ellipsoidShapePrecision) "
570  // " which is the default case. "
571  // " To track a non ellipsoid shape use setEllipsoidShapePrecision(0)") ;
572  // throw(vpTrackingException(vpTrackingException::featureLostError,
573  // "The found dot is invalid")) ;
574  // }
575  // }
576 
577  // if this dot is partially out of the image, return an error tracking.
578  if( !isInImage( I ) )
579  {
580  vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
582  "No dot was found")) ;
583  }
584 
585  // Get dots center of gravity
586  // unsigned int u = (unsigned int) this->cog.get_u();
587  // unsigned int v = (unsigned int) this->cog.get_v();
588  // Updates the min and max gray levels for the next iteration
589  // double Ip = pow((double)I[v][u]/255,1/gamma);
590  double Ip = pow(getMeanGrayLevel()/255,1/gamma);
591  //printf("current value of gray level center : %i\n", I[v][u]);
592 
593  //getMeanGrayLevel(I);
594  if(Ip - (1 - grayLevelPrecision)<0){
595  gray_level_min = 0 ;
596  }
597  else{
598  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
599  if (gray_level_min > 255)
600  gray_level_min = 255;
601  }
602  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
603  if (gray_level_max > 255)
604  gray_level_max = 255;
605 
606  //printf("%i %i \n",gray_level_max,gray_level_min);
607  if (graphics) {
608  // display a red cross at the center of gravity's location in the image.
609 
610  vpDisplay::displayCross(I, this->cog, 3*thickness+8, vpColor::red, thickness);
611  //vpDisplay::flush(I);
612  }
613 }
614 
633 void
635 {
636  track(I);
637 
638  ip = this->cog;
639 }
640 
642 
648 double vpDot2::getWidth() const
649 {
650  return width;
651 }
652 
658 double vpDot2::getHeight() const
659 {
660  return height;
661 }
662 
668 double vpDot2::getArea() const
669 {
670  return fabs(surface);
671 }
672 
679 {
680  return grayLevelPrecision;
681 }
682 
689 {
690  return sizePrecision;
691 }
692 
701 {
702  return ellipsoidShapePrecision;
703 }
704 
711  return maxSizeSearchDistancePrecision;
712 }
713 
717 double vpDot2::getDistance( const vpDot2& distantDot ) const
718 {
719  vpImagePoint cogDistantDot = distantDot.getCog();
720  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
721  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
722  return sqrt( diff_u*diff_u + diff_v*diff_v );
723 }
724 
725 
727 
728 
738 void vpDot2::setWidth( const double & w )
739 {
740  this->width = w;
741 }
742 
753 void vpDot2::setHeight( const double & h )
754 {
755  this->height = h;
756 }
757 
767 void vpDot2::setArea( const double & a )
768 {
769  this->surface = a;
770 }
771 
788 void vpDot2::setGrayLevelPrecision( const double & precision )
789 {
790  double epsilon = 0.05;
791  if( grayLevelPrecision<epsilon )
792  {
793  this->grayLevelPrecision = epsilon;
794  }
795  else if( grayLevelPrecision>1 )
796  {
797  this->grayLevelPrecision = 1.0;
798  }
799  else
800  {
801  this->grayLevelPrecision = precision;
802  }
803 }
818 void vpDot2::setSizePrecision( const double & precision )
819 {
820  if( sizePrecision<0 )
821  {
822  this->sizePrecision = 0;
823  }
824  else if( sizePrecision>1 )
825  {
826  this->sizePrecision = 1.0;
827  }
828  else
829  {
830  this->sizePrecision = precision;
831  }
832 }
833 
863 void vpDot2::setEllipsoidShapePrecision(const double & precision) {
864 
865  if( ellipsoidShapePrecision<0 )
866  {
867  this->ellipsoidShapePrecision = 0;
868  }
869  else if( ellipsoidShapePrecision>1 )
870  {
871  this->ellipsoidShapePrecision = 1.0;
872  }
873  else
874  {
875  this->ellipsoidShapePrecision = precision;
876  }
877 }
878 
892 void vpDot2::setMaxSizeSearchDistancePrecision( const double & precision )
893 {
894  double epsilon = 0.05;
895  if( maxSizeSearchDistancePrecision<epsilon )
896  {
897  this-> maxSizeSearchDistancePrecision = epsilon;
898  }
899  else if( maxSizeSearchDistancePrecision >1 )
900  {
901  this->maxSizeSearchDistancePrecision = 1.0;
902  }
903  else
904  {
905  this->maxSizeSearchDistancePrecision = precision;
906  }
907 }
908 
917 void
919 {
920  setArea(I, 0, 0, I.getWidth(), I.getHeight());
921 }
922 
935 void
937  int u, int v,
938  unsigned int w, unsigned int h)
939 {
940  unsigned int image_w = I.getWidth();
941  unsigned int image_h = I.getHeight();
942 
943  // Bounds the area to the image
944  if (u < 0) u = 0;
945  else if (u >= (int)image_w) u = (int)image_w - 1;
946  if (v < 0) v = 0;
947  else if (v >= (int)image_h) v = (int)image_h - 1;
948 
949  if (((unsigned int)u + w) > image_w) w = image_w - (unsigned int)u - 1;
950  if (((unsigned int)v + h) > image_h) h = image_h - (unsigned int)v - 1;
951 
952  area.setRect(u, v, w, h);
953 }
954 
962 void
963  vpDot2::setArea(const vpRect & a)
964 {
965  area = a;
966 }
967 
969 
1019 void vpDot2::searchDotsInArea(const vpImage<unsigned char>& I, std::list<vpDot2> &niceDots)
1020 {
1021  searchDotsInArea( I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
1022 }
1023 
1046  int area_u,
1047  int area_v,
1048  unsigned int area_w,
1049  unsigned int area_h,
1050  std::list<vpDot2> &niceDots)
1051 
1052 {
1053  // clear the list of nice dots
1054  niceDots.clear();
1055 
1056  // Fit the input area in the image; we keep only the common part between this
1057  // area and the image.
1058  setArea(I, area_u, area_v, area_w, area_h);
1059 
1060  // compute the size of the search grid
1061  unsigned int gridWidth;
1062  unsigned int gridHeight;
1063  getGridSize( gridWidth, gridHeight );
1064 
1065  if (graphics) {
1066  // Display the area were the dot is search
1067  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
1068  //vpDisplay::flush(I);
1069  }
1070 
1071 #ifdef DEBUG
1073  vpDisplay::flush(I);
1074 #endif
1075  // start the search loop; for all points of the search grid,
1076  // test if the pixel belongs to a valid dot.
1077  // if it is so eventually add it to the vector of valid dots.
1078  std::list<vpDot2> badDotsVector;
1079  std::list<vpDot2>::iterator itnice;
1080  std::list<vpDot2>::iterator itbad;
1081 
1082  vpDot2* dotToTest = NULL;
1083  vpDot2 tmpDot;
1084 
1085  unsigned int area_u_min = (unsigned int) area.getLeft();
1086  unsigned int area_u_max = (unsigned int) area.getRight();
1087  unsigned int area_v_min = (unsigned int) area.getTop();
1088  unsigned int area_v_max = (unsigned int) area.getBottom();
1089 
1090  unsigned int u, v;
1091  vpImagePoint cogTmpDot;
1092 
1093  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1094  {
1095  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1096  {
1097  // if the pixel we're in doesn't have the right color (outside the
1098  // graylevel interval), no need to check further, just get to the
1099  // next grid intersection.
1100  if( !hasGoodLevel(I, u, v) ) continue;
1101 
1102  // Test if an other germ is inside the bounding box of a dot previously
1103  // detected
1104  bool good_germ = true;
1105 
1106  itnice = niceDots.begin();
1107  while( itnice != niceDots.end() && good_germ == true) {
1108  tmpDot = *itnice;
1109 
1110  cogTmpDot = tmpDot.getCog();
1111  double u0 = cogTmpDot.get_u();
1112  double v0 = cogTmpDot.get_v();
1113  double half_w = tmpDot.getWidth() / 2.;
1114  double half_h = tmpDot.getHeight() / 2.;
1115 
1116  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1117  v >= (v0-half_h) && v <= (v0+half_h) ) {
1118  // Germ is in a previously detected dot
1119  good_germ = false;
1120  }
1121  ++ itnice;
1122  }
1123 
1124  if (! good_germ)
1125  continue;
1126 
1127  // Compute the right border position for this possible germ
1128  unsigned int border_u;
1129  unsigned int border_v;
1130  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1131  // germ is not good.
1132  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1133  u = border_u;
1134  v = border_v;
1135  continue;
1136  }
1137 
1138  itbad = badDotsVector.begin();
1139 #define vpBAD_DOT_VALUE (*itbad)
1140  vpImagePoint cogBadDot;
1141 
1142  while( itbad != badDotsVector.end() && good_germ == true) {
1143  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1144  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1145  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1146  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max){
1147  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1148  while (it_edges != ip_edges_list.end() && good_germ == true){
1149  // Test if the germ belong to a previously detected dot:
1150  // - from the germ go right to the border and compare this
1151  // position to the list of pixels of previously detected dots
1152  cogBadDot = *it_edges;
1153  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1154  if( (std::fabs(border_u - cogBadDot.get_u()) <= vpMath::maximum(std::fabs((double)border_u), std::fabs(cogBadDot.get_u()))*std::numeric_limits<double>::epsilon() )
1155  &&
1156  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() )) {
1157  good_germ = false;
1158  }
1159  ++ it_edges;
1160  }
1161  }
1162  ++itbad;
1163  }
1164 #undef vpBAD_DOT_VALUE
1165 
1166  if (! good_germ) {
1167  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1168  u = border_u;
1169  v = border_v;
1170  continue;
1171  }
1172 
1173  vpTRACE(4, "Try germ (%d, %d)", u, v);
1174 
1175  vpImagePoint germ;
1176  germ.set_u( u );
1177  germ.set_v( v );
1178 
1179  // otherwise estimate the width, height and surface of the dot we
1180  // created, and test it.
1181  if( dotToTest != NULL ) delete dotToTest;
1182  dotToTest = getInstance();
1183  dotToTest->setCog( germ );
1184  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1185  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1187  dotToTest->setSizePrecision( getSizePrecision() );
1188  dotToTest->setGraphics( graphics );
1189  dotToTest->setGraphicsThickness( thickness );
1190  dotToTest->setComputeMoments( true );
1191  dotToTest->setArea( area );
1192  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1193 
1194  // first compute the parameters of the dot.
1195  // if for some reasons this caused an error tracking
1196  // (dot partially out of the image...), check the next intersection
1197  if( dotToTest->computeParameters( I ) == false ) {
1198  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1199  u = border_u;
1200  v = border_v;
1201  continue;
1202  }
1203  // if the dot to test is valid,
1204  if( dotToTest->isValid( I, *this ) )
1205  {
1206  vpImagePoint cogDotToTest = dotToTest->getCog();
1207  // Compute the distance to the center. The center used here is not the
1208  // area center available by area.getCenter(area_center_u,
1209  // area_center_v) but the center of the input area which may be
1210  // partially outside the image.
1211 
1212  double area_center_u = area_u + area_w/2.0 - 0.5;
1213  double area_center_v = area_v + area_h/2.0 - 0.5;
1214 
1215  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1216  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1217  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1218 
1219  bool stopLoop = false;
1220  itnice = niceDots.begin();
1221 
1222  while( itnice != niceDots.end() && stopLoop == false )
1223  {
1224  tmpDot = *itnice;
1225 
1226  //double epsilon = 0.001; // detecte +sieurs points
1227  double epsilon = 3.0;
1228  // if the center of the dot is the same than the current
1229  // don't add it, test the next point of the grid
1230  cogTmpDot = tmpDot.getCog();
1231 
1232  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1233  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1234  {
1235  stopLoop = true;
1236  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1237  u = border_u;
1238  v = border_v;
1239  continue;
1240  }
1241 
1242  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1243  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1244  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1245  otherDiff_v*otherDiff_v );
1246 
1247 
1248  // if the distance of the curent vector element to the center
1249  // is greater than the distance of this dot to the center,
1250  // then add this dot before the current vector element.
1251  if( otherDist > thisDist )
1252  {
1253  niceDots.insert(itnice, *dotToTest );
1254  ++ itnice;
1255  stopLoop = true;
1256  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1257  u = border_u;
1258  v = border_v;
1259  continue;
1260  }
1261  ++itnice;
1262  }
1263  vpTRACE(4, "End while (%d, %d)", u, v);
1264 
1265  // if we reached the end of the vector without finding the dot
1266  // or inserting it, insert it now.
1267  if( itnice == niceDots.end() && stopLoop == false )
1268  {
1269  niceDots.push_back( *dotToTest );
1270  }
1271  }
1272  else {
1273  // Store bad dots
1274  badDotsVector.push_front( *dotToTest );
1275  }
1276  }
1277  }
1278  if( dotToTest != NULL ) delete dotToTest;
1279 }
1280 
1301 bool vpDot2::isValid(const vpImage<unsigned char>& I, const vpDot2& wantedDot )
1302 {
1303  double size_precision = wantedDot.getSizePrecision();
1304  double ellipsoidShape_precision = wantedDot.getEllipsoidShapePrecision();
1305  double epsilon = 0.001;
1306 
1307  //
1308  // First, check the width, height and surface of the dot. Those parameters
1309  // must be the same.
1310  //
1311  //if ( (wantedDot.getWidth() != 0)
1312  // && (wantedDot.getHeight() != 0)
1313  // && (wantedDot.getArea() != 0) )
1314  if ( (std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon())
1315  &&
1316  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon())
1317  &&
1318  (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon()) )
1319  // if (size_precision!=0){
1320  if (std::fabs(size_precision) > std::numeric_limits<double>::epsilon()){
1321 #ifdef DEBUG
1322  std::cout << "test size precision......................\n";
1323  std::cout << "wanted dot: " << "w=" << wantedDot.getWidth()
1324  << " h=" << wantedDot.getHeight()
1325  << " s=" << wantedDot.getArea()
1326  << " precision=" << size_precision
1327  << " epsilon=" << epsilon << std::endl;
1328  std::cout << "dot found: " << "w=" << getWidth()
1329  << " h=" << getHeight()
1330  << " s=" << getArea() << std::endl;
1331 #endif
1332  if( ( wantedDot.getWidth()*size_precision-epsilon < getWidth() ) == false )
1333  {
1334  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1335  cog.get_u(), cog.get_v());
1336 #ifdef DEBUG
1337  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1338 #endif
1339  return false;
1340  }
1341 
1342  if( ( getWidth() < wantedDot.getWidth()/(size_precision+epsilon ) )== false )
1343  {
1344  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1345  cog.get_u(), cog.get_v());
1346 #ifdef DEBUG
1347  printf("Bad width %g > %g for dot (%g, %g)\n",
1348  getWidth(), wantedDot.getWidth()/(size_precision+epsilon),
1349  cog.get_u(), cog.get_v());
1350 #endif
1351  return false;
1352  }
1353 
1354  if( ( wantedDot.getHeight()*size_precision-epsilon < getHeight() ) == false )
1355  {
1356  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1357  cog.get_u(), cog.get_v());
1358 #ifdef DEBUG
1359  printf("Bad height %g > %g for dot (%g, %g)\n",
1360  wantedDot.getHeight()*size_precision-epsilon, getHeight(),
1361  cog.get_u(), cog.get_v());
1362 #endif
1363  return false;
1364  }
1365 
1366  if( ( getHeight() < wantedDot.getHeight()/(size_precision+epsilon )) == false )
1367  {
1368  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1369  cog.get_u(), cog.get_v());
1370 #ifdef DEBUG
1371  printf("Bad height %g > %g for dot (%g, %g)\n",
1372  getHeight(), wantedDot.getHeight()/(size_precision+epsilon),
1373  cog.get_u(), cog.get_v());
1374 #endif
1375  return false;
1376  }
1377 
1378  if( ( wantedDot.getArea()*(size_precision*size_precision)-epsilon < getArea() ) == false )
1379  {
1380  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1381  cog.get_u(), cog.get_v());
1382 #ifdef DEBUG
1383  printf("Bad surface %g > %g for dot (%g, %g)\n",
1384  wantedDot.getArea()*(size_precision*size_precision)-epsilon,
1385  getArea(),
1386  cog.get_u(), cog.get_v());
1387 #endif
1388  return false;
1389  }
1390 
1391  if( ( getArea() < wantedDot.getArea()/(size_precision*size_precision+epsilon )) == false )
1392  {
1393  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1394  cog.get_u(), cog.get_v());
1395 #ifdef DEBUG
1396  printf("Bad surface %g < %g for dot (%g, %g)\n",
1397  getArea(), wantedDot.getArea()/(size_precision*size_precision+epsilon),
1398  cog.get_u(), cog.get_v());
1399 #endif
1400  return false;
1401  }
1402  }
1403  //
1404  // Now we can proceed to more advanced (and costy) checks.
1405  // First check there is a white (>level) elipse within dot
1406  // Then check the dot is surrounded by a black ellipse.
1407  //
1408  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1409  int nb_bad_points = 0;
1410  int nb_max_bad_points = (int)(nb_point_to_test*allowedBadPointsPercentage_);
1411  double step_angle = 2*M_PI / nb_point_to_test;
1412 
1413  // if (ellipsoidShape_precision != 0 && compute_moment) {
1414  if (std::fabs(ellipsoidShape_precision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1415  // std::cout << "test shape precision......................\n";
1416  // See F. Chaumette. Image moments: a general and useful set of features
1417  // for visual servoing. IEEE Trans. on Robotics, 20(4):713-723, August 2004.
1418 
1419  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1420  // = m11 - m10 * m01 / m00
1421  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1422  // = m20 - m10^2 / m00
1423  // mu02 = m02 - m01^2 / m00
1424  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1425  //
1426  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1427  //
1428  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1429 
1430  //we compute parameters of the estimated ellipse
1431  double tmp1 = (m01*m01 -m10*m10)/m00+(m20-m02);
1432  double tmp2 = m11 -m10*m01/m00 ;
1433  double Sqrt = sqrt(tmp1*tmp1 + 4*tmp2*tmp2);
1434  double a1 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 + Sqrt));
1435  double a2 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 - Sqrt));
1436  double alpha = 0.5*atan2(2*(m11*m00-m10*m01),
1437  ((m20-m02)*m00-m10*m10+m01*m01));
1438 
1439  // to be able to track small dots, minorize the ellipsoid radius for the
1440  // inner test
1441  a1 -= 1.0;
1442  a2 -= 1.0;
1443 
1444  double innerCoef = ellipsoidShape_precision ;
1445  unsigned int u, v;
1446  double cog_u = this->cog.get_u();
1447  double cog_v = this->cog.get_v();
1448 
1449  vpImagePoint ip;
1450  nb_bad_points = 0;
1451  for( double theta = 0. ; theta<2*M_PI ; theta+= step_angle ) {
1452  u = (unsigned int) (cog_u + innerCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
1453  v = (unsigned int) (cog_v + innerCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
1454  if( ! this->hasGoodLevel( I, u, v) ) {
1455  // vpTRACE("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g)",
1456  // u, v, cog_u, cog_v);
1457 #ifdef DEBUG
1458  printf("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
1459  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1460 #endif
1461  //return false;
1462  nb_bad_points ++;
1463  }
1464  if (graphics) {
1465  for (unsigned int t=0; t< thickness; t++) {
1466  ip.set_u( u + t );
1467  ip.set_v( v );
1469  }
1470  }
1471 #ifdef DEBUG
1473  vpDisplay::flush(I);
1474 #endif
1475  }
1476  if (nb_bad_points > nb_max_bad_points)
1477  {
1478 #ifdef DEBUG
1479  printf("Inner ellipse has %d bad points. Max allowed is %d\n",
1480  nb_bad_points, nb_max_bad_points);
1481 #endif
1482  return false;
1483  }
1484  // to be able to track small dots, maximize the ellipsoid radius for the
1485  // inner test
1486  a1 += 2.0;
1487  a2 += 2.0;
1488 
1489  double outCoef = 2-ellipsoidShape_precision; //1.6;
1490  nb_bad_points = 0;
1491  for( double theta=0. ; theta<2*M_PI ; theta+= step_angle ) {
1492  u = (unsigned int) (cog_u + outCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
1493  v = (unsigned int) (cog_v + outCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
1494 #ifdef DEBUG
1495  //vpDisplay::displayRectangle(I, area, vpColor::yellow);
1496  vpDisplay::displayCross( I, v, u, 7, vpColor::purple ) ;
1497  vpDisplay::flush(I);
1498 #endif
1499  // If outside the area, continue
1500  if ((double)u < area.getLeft() || (double)u > area.getRight()
1501  || (double)v < area.getTop() || (double)v > area.getBottom()) {
1502  continue;
1503  }
1504  if( ! this->hasReverseLevel( I, u, v ) ) {
1505  // vpTRACE("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g)",
1506  // u, v, cog_u, cog_v);
1507 #ifdef DEBUG
1508  printf("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
1509  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1510 #endif
1511  nb_bad_points ++;
1512  //return false;
1513  }
1514  if (graphics) {
1515  for(unsigned int t=0; t<thickness; t++) {
1516  ip.set_u( u + t);
1517  ip.set_v( v );
1518 
1520  }
1521  }
1522  }
1523  }
1524  if (nb_bad_points > nb_max_bad_points)
1525  {
1526 #ifdef DEBUG
1527  printf("Outside ellipse has %d bad points. Max allowed is %d\n",
1528  nb_bad_points, nb_max_bad_points);
1529 #endif
1530  return false;
1531  }
1532 
1533  return true;
1534 }
1535 
1536 
1537 
1555 bool vpDot2::hasGoodLevel(const vpImage<unsigned char>& I,
1556  const unsigned int &u,
1557  const unsigned int &v) const
1558 {
1559  if( !isInArea( u, v ) )
1560  return false;
1561 
1562  if( I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
1563  {
1564  return true;
1565  }
1566  else
1567  {
1568  return false;
1569  }
1570 }
1571 
1572 
1585 bool vpDot2::hasReverseLevel(const vpImage<unsigned char>& I,
1586  const unsigned int &u,
1587  const unsigned int &v) const
1588 {
1589 
1590  if( !isInArea( u, v ) )
1591  return false;
1592 
1593  if( I[v][u] < gray_level_min || I[v][u] > gray_level_max)
1594  {
1595  return true;
1596  }
1597  else
1598  {
1599  return false;
1600  }
1601 }
1602 
1603 
1612 vpDot2* vpDot2::getInstance()
1613 {
1614  return new vpDot2();
1615 }
1616 
1632 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const
1633 {
1634  freeman_chain = direction_list;
1635 }
1636 
1637 
1638 
1639 /******************************************************************************
1640  *
1641  * PRIVATE METHODS
1642  *
1643  ******************************************************************************/
1644 
1645 
1646 
1678 bool vpDot2::computeParameters(const vpImage<unsigned char> &I,
1679  const double &_u,
1680  const double &_v)
1681 {
1682  direction_list.clear();
1683  ip_edges_list.clear();
1684 
1685  double est_u = _u; // estimated
1686  double est_v = _v;
1687 
1688  // if u has default value, set it to the actual center value
1689  //if( est_u == -1.0 )
1690  if( std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u),1.)*std::numeric_limits<double>::epsilon() )
1691  {
1692  est_u = this->cog.get_u();
1693  }
1694 
1695  // if v has default value, set it to the actual center value
1696  //if( est_v == -1.0 )
1697  if( std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v),1.)*std::numeric_limits<double>::epsilon() )
1698  {
1699  est_v = this->cog.get_v();
1700  }
1701 
1702  // if the estimated position of the dot is out of the image, not need to continue,
1703  // return an error tracking
1704  if( !isInArea( (unsigned int) est_u, (unsigned int) est_v ) )
1705  {
1706  vpDEBUG_TRACE(3, "Initial pixel coordinates (%d, %d) for dot tracking are not in the area",
1707  (int) est_u, (int) est_v) ;
1708  return false;
1709  }
1710 
1711  bbox_u_min = (int)I.getWidth();
1712  bbox_u_max = 0;
1713  bbox_v_min = (int)I.getHeight();
1714  bbox_v_max = 0;
1715 
1716  // if the first point doesn't have the right level then there's no point to
1717  // continue.
1718  if( !hasGoodLevel( I, (unsigned int) est_u, (unsigned int) est_v ) )
1719  {
1720  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates",
1721  (int) est_u, (int) est_v) ;
1722  return false;
1723  }
1724 
1725  // find the border
1726 
1727  if(!findFirstBorder(I, (unsigned int) est_u, (unsigned int) est_v,
1728  this->firstBorder_u, this->firstBorder_v)) {
1729 
1730  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates",
1731  (int) est_u, (int) est_v) ;
1732  return false;
1733  }
1734 
1735  unsigned int dir = 6;
1736 
1737  // Determine the first element of the Freeman chain
1738  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
1739  unsigned int firstDir = dir;
1740 
1741  // if we are now out of the image, return an error tracking
1742  if( !isInArea( this->firstBorder_u, this->firstBorder_v ) )
1743  {
1744  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area",
1745  this->firstBorder_u, this->firstBorder_v);
1746  return false;
1747  }
1748 
1749  // store the new direction and dot border coordinates.
1750  direction_list.push_back( dir );
1751  vpImagePoint ip;
1752  ip.set_u( this->firstBorder_u );
1753  ip.set_v( this->firstBorder_v );
1754 
1755  ip_edges_list.push_back( ip );
1756 
1757  int border_u = (int)this->firstBorder_u;
1758  int border_v = (int)this->firstBorder_v;
1759 
1760  // vpTRACE("-----------------------------------------");
1761  // vpTRACE("first border_u: %d border_v: %d dir: %d",
1762  // this->firstBorder_u, this->firstBorder_v,firstDir);
1763  int du, dv;
1764  float dS, dMu, dMv, dMuv, dMu2, dMv2;
1765  m00 = 0.0;
1766  m10 = 0.0;
1767  m01 = 0.0;
1768  m11 = 0.0;
1769  m20 = 0.0;
1770  m02 = 0.0;
1771  // while we didn't come back to the first point, follow the border
1772  do {
1773  // if it was asked, show the border
1774  if (graphics) {
1775  for(int t=0; t< (int)thickness; t++) {
1776  ip.set_u ( border_u + t);
1777  ip.set_v ( border_v );
1778 
1780  }
1781  //vpDisplay::flush(I);
1782  }
1783 #ifdef DEBUG
1784  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1785  vpDisplay::flush(I);
1786 #endif
1787  // Determine the increments for the parameters
1788  computeFreemanParameters(border_u, border_v, dir, du, dv,
1789  dS, // surface
1790  dMu, dMv, // first order moments
1791  dMuv, dMu2, dMv2); // second order moment
1792 
1793  // Update the parameters
1794  border_u += du; // Next position on the border
1795  border_v += dv;
1796  m00 += dS; // enclosed area
1797  m10 += dMu; // First order moment along v axis
1798  m01 += dMv; // First order moment along u axis
1799  if (compute_moment) {
1800  m11 += dMuv; // Second order moment
1801  m20 += dMu2; // Second order moment along v axis
1802  m02 += dMv2; // Second order moment along u axis
1803  }
1804  // if we are now out of the image, return an error tracking
1805  if( !isInArea( (unsigned int)border_u, (unsigned int)border_v ) ) {
1806 
1807  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
1808  // Can Occur on a single pixel dot located on the top border
1809  return false;
1810  }
1811 
1812  // store the new direction and dot border coordinates.
1813 
1814  direction_list.push_back( dir );
1815 
1816  ip.set_u( border_u );
1817  ip.set_v( border_v );
1818  ip_edges_list.push_back( ip );
1819 
1820  // vpDisplay::getClick(I);
1821 
1822  // update the extreme point of the dot.
1823  if( border_v < bbox_v_min ) bbox_v_min = border_v;
1824  if( border_v > bbox_v_max ) bbox_v_max = border_v;
1825  if( border_u < bbox_u_min ) bbox_u_min = border_u;
1826  if( border_u > bbox_u_max ) bbox_u_max = border_u;
1827 
1828  // move around the tracked entity by following the border.
1829  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
1830  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)",
1831  border_u, border_v);
1832  return false;
1833  }
1834 
1835  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v, dir);
1836 
1837  }
1838  while( (getFirstBorder_u() != (unsigned int)border_u
1839  || getFirstBorder_v() != (unsigned int)border_v
1840  || firstDir != dir) &&
1841  isInArea( (unsigned int)border_u, (unsigned int)border_v ) );
1842 
1843 #ifdef VP_DEBUG
1844 #if VP_DEBUG_MODE == 3
1845  vpDisplay::flush(I);
1846 #endif
1847 #endif
1848 
1849  // if the surface is one or zero , the center of gravity wasn't properly
1850  // detected. Return an error tracking.
1851  //if( m00 == 0 || m00 == 1 )
1852  if( std::fabs(m00) <= std::numeric_limits<double>::epsilon()
1853  || std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.)*std::numeric_limits<double>::epsilon() )
1854  {
1855  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
1856  return false;
1857  }
1858  else // compute the center
1859  {
1860  // this magic formula gives the coordinates of the center of gravity
1861  double tmpCenter_u = m10 / m00;
1862  double tmpCenter_v = m01 / m00;
1863 
1864  //Updates the central moments
1865  if (compute_moment)
1866  {
1867  mu11 = m11 - tmpCenter_u*m01;
1868  mu02 = m02 - tmpCenter_v*m01;
1869  mu20 = m20 - tmpCenter_u*m10;
1870  }
1871 
1872 
1873  // check the center is in the image... never know...
1874  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
1875  // (unsigned int)tmpCenter_v ) )
1876  // {
1877  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has not a good in level", tmpCenter_u, tmpCenter_v);
1878  // return false;
1879  // }
1880 
1881  cog.set_u( tmpCenter_u );
1882  cog.set_v( tmpCenter_v );
1883  }
1884 
1885  width = bbox_u_max - bbox_u_min + 1;
1886  height = bbox_v_max - bbox_v_min + 1;
1887  surface = m00;
1888 
1889  computeMeanGrayLevel(I);
1890  return true;
1891 }
1892 
1893 
1909 bool
1910  vpDot2::findFirstBorder(const vpImage<unsigned char> &I,
1911  const unsigned int &u,
1912  const unsigned int &v,
1913  unsigned int &border_u,
1914  unsigned int &border_v)
1915 {
1916  // find the border
1917 
1918  // NOTE:
1919  // from here we use int and not double. This is because we don't have
1920  // rounding problems and it's actually more a trouble than smth else to
1921  // work with double when navigating around the dot.
1922  border_u = u;
1923  border_v = v;
1924  double epsilon =0.001;
1925 
1926 #ifdef DEBUG
1927  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
1928 #endif
1929  while( hasGoodLevel( I, border_u+1, border_v ) &&
1930  border_u < area.getRight()/*I.getWidth()*/ ) {
1931  // if the width of this dot was initialised and we already crossed the dot
1932  // on more than the max possible width, no need to continue, return an
1933  // error tracking
1934  if( getWidth() > 0 && ( border_u - u ) > getWidth()/(getMaxSizeSearchDistancePrecision()+epsilon) ) {
1935  vpDEBUG_TRACE(3, "The found dot (%d, %d, %d) has a greater width than the required one", u, v, border_u);
1936  return false;
1937  }
1938 #ifdef DEBUG
1939  vpDisplay::displayPoint(I, border_v, border_u+1, vpColor::green);
1940  vpDisplay::flush(I);
1941 #endif
1942 
1943  border_u++;
1944  }
1945  return true;
1946 }
1947 
1948 
1967 bool
1968  vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I,
1969  const unsigned int &u,
1970  const unsigned int &v,
1971  unsigned int &element)
1972 {
1973 
1974  if (hasGoodLevel( I, u, v )) {
1975  unsigned int _u = u;
1976  unsigned int _v = v;
1977  // get the point on the right of the point passed in
1978  updateFreemanPosition( _u, _v, (element + 2) %8 );
1979  if (hasGoodLevel( I, _u, _v )) {
1980  element = (element + 2) % 8; // turn right
1981  }
1982  else {
1983  unsigned int _u1 = u;
1984  unsigned int _v1 = v;
1985  updateFreemanPosition( _u1, _v1, (element + 1) %8 );
1986 
1987  if ( hasGoodLevel( I, _u1, _v1 )) {
1988  element = (element + 1) % 8; // turn diag right
1989  }
1990  else {
1991  unsigned int _u2 = u;
1992  unsigned int _v2 = v;
1993  updateFreemanPosition( _u2, _v2, element ); // same direction
1994 
1995  if ( hasGoodLevel( I, _u2, _v2 )) {
1996  //element = element; // keep same dir
1997  }
1998  else {
1999  unsigned int _u3 = u;
2000  unsigned int _v3 = v;
2001  updateFreemanPosition( _u3, _v3, (element + 7) %8 ); // diag left
2002 
2003  if ( hasGoodLevel( I, _u3, _v3 )) {
2004  element = (element + 7) %8; // turn diag left
2005  }
2006  else {
2007  unsigned int _u4 = u;
2008  unsigned int _v4 = v;
2009  updateFreemanPosition( _u4, _v4, (element + 6) %8 ); // left
2010 
2011  if ( hasGoodLevel( I, _u4, _v4 )) {
2012  element = (element + 6) %8 ; // turn left
2013  }
2014  else {
2015  unsigned int _u5 = u;
2016  unsigned int _v5 = v;
2017  updateFreemanPosition( _u5, _v5, (element + 5) %8 ); // left
2018 
2019  if ( hasGoodLevel( I, _u5, _v5 )) {
2020  element = (element + 5) %8 ; // turn diag down
2021  }
2022  else {
2023  unsigned int _u6 = u;
2024  unsigned int _v6 = v;
2025  updateFreemanPosition( _u6, _v6, (element + 4) %8 ); // left
2026 
2027  if ( hasGoodLevel( I, _u6, _v6 )) {
2028  element = (element + 4) %8 ; // turn down
2029  }
2030  else {
2031  unsigned int _u7 = u;
2032  unsigned int _v7 = v;
2033  updateFreemanPosition( _u7, _v7, (element + 3) %8 ); // diag
2034 
2035  if ( hasGoodLevel( I, _u7, _v7 )) {
2036  element = (element + 3) %8 ; // turn diag right down
2037  }
2038  else {
2039  // No neighbor with a good level
2040  //
2041  return false;
2042  }
2043  }
2044  }
2045  }
2046  }
2047  }
2048  }
2049  }
2050  }
2051 
2052  else {
2053  return false;
2054  }
2055 
2056  return true;
2057 
2058 }
2059 
2091 void
2092  vpDot2::computeFreemanParameters(const int &u_p,
2093  const int &v_p,
2094  unsigned int &element,
2095  int &du, int &dv,
2096  float &dS,
2097  float &dMu, float &dMv,
2098  float &dMuv,
2099  float &dMu2, float &dMv2)
2100 {
2101  du = 0;
2102  dv = 0;
2103  dMuv = 0;
2104  dMu2 = 0;
2105  dMv2 = 0;
2106 
2107  /*
2108  3 2 1
2109  \ | /
2110  \|/
2111  4 ------- 0
2112  /|\
2113  / | \
2114  5 6 7
2115  */
2116  switch(element) {
2117  case 0: // go right
2118  du = 1;
2119  dS = (float) v_p;
2120  dMu = 0.0;
2121  dMv = (float)(0.5 * v_p * v_p);
2122  if (compute_moment) {
2123  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
2124  dMu2 = 0;
2125  dMv2 = (float)(1.0/ 3. * v_p * v_p * v_p);
2126  }
2127  break;
2128 
2129  case 1: // go right top
2130  du = 1;
2131  dv = 1;
2132  dS = (float)(v_p + 0.5);
2133  dMu = - (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2134  dMv = (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2135  if (compute_moment) {
2136  float half_u_p = (float)(0.5*u_p);
2137  dMuv = (float)(v_p*v_p*(0.25+half_u_p) + v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2138  dMu2 = (float)(-1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1./12.0);
2139  dMv2 = (float)( 1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1./12.0);
2140  }
2141  break;
2142 
2143  case 2: // go top
2144  dv = 1;
2145  dS = 0.0;
2146  dMu = (float)(- 0.5 * u_p * u_p);
2147  dMv = 0.0;
2148  if (compute_moment) {
2149  dMuv = 0;
2150  dMu2 = (float)(-1.0/ 3. * u_p * u_p * u_p);
2151  dMv2 = 0;
2152  }
2153  break;
2154 
2155  case 3:
2156  du = -1;
2157  dv = 1;
2158  dS = (float)(- v_p - 0.5);
2159  dMu = - (float)(0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2160  dMv = - (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2161  if (compute_moment) {
2162  float half_u_p = (float)(0.5*u_p);
2163  dMuv = (float)(v_p*v_p*(0.25-half_u_p) + v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2164  dMu2 = (float)(-1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2165  dMv2 = (float)(-1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1./12.0);
2166  }
2167  break;
2168 
2169  case 4:
2170  du = -1;
2171  dS = (float)(- v_p);
2172  dMv = (float)(- 0.5 * v_p * v_p);
2173  dMu = 0.0;
2174  if (compute_moment) {
2175  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2176  dMu2 = 0;
2177  dMv2 = (float)(-1.0/ 3. * v_p * v_p * v_p);
2178  }
2179  break;
2180 
2181  case 5:
2182  du = -1;
2183  dv = -1;
2184  dS = (float)(- v_p + 0.5);
2185  dMu = (float)( 0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2186  dMv = (float)(- (0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0));
2187  if (compute_moment) {
2188  float half_u_p = (float)(0.5*u_p);
2189  dMuv = (float)(v_p*v_p*(0.25-half_u_p) - v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2190  dMu2 = (float)( 1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2191  dMv2 = (float)(-1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2192  }
2193  break;
2194 
2195  case 6:
2196  dv = -1;
2197  dS = 0.0;
2198  dMu = (float)(0.5 * u_p * u_p);
2199  dMv = 0.0;
2200  if (compute_moment) {
2201  dMuv = 0;
2202  dMu2 = (float)(1.0/ 3. * u_p * u_p * u_p);
2203  dMv2 = 0;
2204  }
2205  break;
2206 
2207  case 7:
2208  du = 1;
2209  dv = -1;
2210  dS = (float)(v_p - 0.5);
2211  dMu = (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2212  dMv = (float)(0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0);
2213  if (compute_moment) {
2214  float half_u_p = (float)(0.5*u_p);
2215  dMuv = (float)(v_p*v_p*(0.25+half_u_p) - v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2216  dMu2 = (float)(1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1./12.0);
2217  dMv2 = (float)(1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2218  }
2219  break;
2220  }
2221 }
2222 
2223 
2237 void vpDot2::updateFreemanPosition( unsigned int& u, unsigned int& v,
2238  const unsigned int &dir )
2239 {
2240  switch(dir) {
2241  case 0: u += 1; break;
2242  case 1: u += 1; v += 1; break;
2243  case 2: v += 1; break;
2244  case 3: u -= 1; v += 1; break;
2245  case 4: u -= 1; break;
2246  case 5: u -= 1; v -= 1; break;
2247  case 6: v -= 1; break;
2248  case 7: u += 1; v -= 1; break;
2249  }
2250 }
2251 
2263 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const
2264 {
2265  return isInImage( I, cog);
2266 }
2267 
2279 bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
2280 {
2281  unsigned int h = I.getHeight();
2282  unsigned int w = I.getWidth();
2283  double u = ip.get_u();
2284  double v = ip.get_v();
2285 
2286  if( u < 0 || u >= w ) return false;
2287  if( v < 0 || v >= h ) return false;
2288  return true;
2289 }
2290 
2302 bool vpDot2::isInArea( const unsigned int &u, const unsigned int &v) const
2303 {
2304  unsigned int area_u_min = (unsigned int) area.getLeft();
2305  unsigned int area_u_max = (unsigned int) area.getRight();
2306  unsigned int area_v_min = (unsigned int) area.getTop();
2307  unsigned int area_v_max = (unsigned int) area.getBottom();
2308 
2309  if( u < area_u_min || u > area_u_max ) return false;
2310  if( v < area_v_min || v > area_v_max ) return false;
2311  return true;
2312 }
2313 
2314 
2326 void vpDot2::getGridSize( unsigned int &gridWidth, unsigned int &gridHeight )
2327 {
2328  // first get the research grid width and height Note that
2329  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2330  // contained in the dot. We gent this here if the dot is a perfect disc.
2331  // More accurate criterium to define the grid should be implemented if
2332  // necessary
2333  gridWidth = (unsigned int) (getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2334  gridHeight = (unsigned int) (getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2335 
2336  if( gridWidth == 0 ) gridWidth = 1;
2337  if( gridHeight == 0 ) gridHeight = 1;
2338 }
2339 
2340 
2341 
2354 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char>& I)
2355 {
2356  int cog_u = (int)cog.get_u();
2357  int cog_v = (int)cog.get_v();
2358 
2359  unsigned int sum_value =0;
2360  unsigned int nb_pixels =0;
2361 
2362  for(unsigned int i=(unsigned int)this->bbox_u_min; i <=(unsigned int)this->bbox_u_max ; i++){
2363  unsigned int pixel_gray =(unsigned int) I[(unsigned int)cog_v][i];
2364  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2365  sum_value += pixel_gray;
2366  nb_pixels ++;
2367  }
2368  }
2369  for(unsigned int i=(unsigned int)this->bbox_v_min; i <=(unsigned int)this->bbox_v_max ; i++){
2370  unsigned char pixel_gray =I[i][(unsigned int)cog_u];
2371  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2372  sum_value += pixel_gray;
2373  nb_pixels ++;
2374  }
2375  }
2376  if(nb_pixels < 10){ //could be good to choose the min nb points from area of dot
2377  //add diagonals points to have enough point
2378  int imin,imax;
2379  if( (cog_u - bbox_u_min) > (cog_v - bbox_v_min)){
2380  imin=cog_v - bbox_v_min;
2381  }
2382  else{ imin = cog_u - bbox_u_min;}
2383  if( (bbox_u_max - cog_u) > (bbox_v_max - cog_v)){
2384  imax=bbox_v_max - cog_v;
2385  }
2386  else{ imax = bbox_u_max - cog_u;}
2387  for(int i=-imin; i <=imax ; i++){
2388  unsigned int pixel_gray =(unsigned int) I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2389  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2390  sum_value += pixel_gray;
2391  nb_pixels ++;
2392  }
2393  }
2394 
2395  if( (cog_u - bbox_u_min) > (bbox_v_max - cog_v)){
2396  imin = bbox_v_max - cog_v;
2397  }
2398  else{ imin = cog_u - bbox_u_min;}
2399  if( (bbox_u_max - cog_u) > (cog_v - bbox_v_min)){
2400  imax = cog_v - bbox_v_min;
2401  }
2402  else{ imax = bbox_u_max - cog_u;}
2403 
2404  for(int i=-imin; i <=imax ; i++){
2405  unsigned char pixel_gray =I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2406  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2407  sum_value += pixel_gray;
2408  nb_pixels ++;
2409  }
2410  }
2411  }
2412 
2413  if(nb_pixels== 0){
2414  //should never happen
2416  }
2417  else{
2418  mean_gray_level = sum_value/nb_pixels;
2419  }
2420 }
2421 
2422 
2438 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I, vpColor col, bool trackDot)
2439 {
2440  vpMatrix Cogs(n, 2);
2441  vpImagePoint cog;
2442  unsigned int i;
2443  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
2444  if(fromFile)
2445  {
2446  vpMatrix::loadMatrix(dotFile, Cogs);
2447  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
2448  }
2449 
2450  // test number of cogs in file
2451  if(Cogs.getRows() < n)
2452  {
2453  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
2454  fromFile = false;
2455  }
2456 
2457  // read from file and tracks the dots
2458  if(fromFile)
2459  {
2460  try
2461  {
2462  for(i=0;i<n;++i)
2463  {
2464  cog.set_uv(Cogs[i][0], Cogs[i][1]);
2465  dot[i].setGraphics(true);
2466  dot[i].setCog(cog);
2467  if(trackDot)
2468  {
2469  dot[i].initTracking(I,cog);
2470  dot[i].track(I);
2471  vpDisplay::displayCross(I, cog, 10, col);
2472  }
2473  }
2474  }
2475  catch(...)
2476  {
2477  std::cout << "Cannot track dots from file" << std::endl;
2478  fromFile = false;
2479  }
2480  vpDisplay::flush(I);
2481 
2482  // check that dots are far away ones from the other
2483  double d;
2484  for(i=0;i<n && fromFile;++i)
2485  {
2486  d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
2487  for(unsigned int j=0;j<n && fromFile;++j)
2488  if(j!=i)
2489  if(dot[i].getDistance(dot[j]) < d)
2490  {
2491  fromFile = false;
2492  std::cout << "Dots from file seem incoherent" << std::endl;
2493  }
2494  }
2495  }
2496 
2497  if(!fromFile)
2498  {
2499  vpDisplay::display(I);
2500  vpDisplay::flush(I);
2501 
2502  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
2503  for (i = 0; i < n; i++)
2504  {
2505  if(trackDot)
2506  {
2507  dot[i].setGraphics(true);
2508  dot[i].initTracking(I);
2509  cog = dot[i].getCog();
2510  }
2511  else
2512  {
2513  vpDisplay::getClick(I, cog);
2514  dot[i].setCog(cog);
2515  }
2516  Cogs[i][0] = cog.get_u();
2517  Cogs[i][1] = cog.get_v();
2518  vpDisplay::displayCross(I, cog, 10, col);
2519  vpDisplay::flush(I);
2520  }
2521  }
2522 
2523  if (!fromFile & (dotFile != ""))
2524  {
2525  vpMatrix::saveMatrix(dotFile, Cogs);
2526  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
2527  }
2528 
2529  // back to non graphic mode
2530  for(i=0;i<n;++i)
2531  dot[i].setGraphics(false);
2532 
2533  return Cogs;
2534 }
2535 
2545 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I, std::vector<vpImagePoint> &cogs, vpImagePoint* cogStar)
2546 {
2547  unsigned int i;
2548  // tracking
2549  for(i=0;i<n;++i)
2550  {
2551  dot[i].track(I);
2552  cogs.push_back(dot[i].getCog());
2553  }
2554  // trajectories
2555  for(i=n;i<cogs.size();++i)
2556  vpDisplay::displayCircle(I,cogs[i],4,vpColor::green,true);
2557  // initial position
2558  for(i=0;i<n;++i)
2559  vpDisplay::displayCircle(I,cogs[i],4,vpColor::blue,true);
2560  // if exists, desired position
2561  if(cogStar != NULL)
2562  for(i=0;i<n;++i)
2563  {
2564  vpDisplay::displayDotLine(I,cogStar[i],dot[i].getCog(),vpColor::red);
2565  vpDisplay::displayCircle(I,cogStar[i],4,vpColor::red,true);
2566  }
2567  vpDisplay::flush(I);
2568 }
2569 
2585  const std::list<vpImagePoint> &edges_list, vpColor color,
2586  unsigned int thickness)
2587 {
2588  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
2589  std::list<vpImagePoint>::const_iterator it;
2590 
2591  for (it = edges_list.begin(); it != edges_list.end(); ++it)
2592  {
2593  vpDisplay::displayPoint(I, *it, color);
2594  }
2595 }
2596 
2612  const std::list<vpImagePoint> &edges_list, vpColor color,
2613  unsigned int thickness)
2614 {
2615  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
2616  std::list<vpImagePoint>::const_iterator it;
2617 
2618  for (it = edges_list.begin(); it != edges_list.end(); ++it)
2619  {
2620  vpDisplay::displayPoint(I, *it, color);
2621  }
2622 }
2623 
2629 VISP_EXPORT std::ostream& operator<< (std::ostream& os, vpDot2& d) {
2630  return (os << "(" << d.getCog() << ")" ) ;
2631 } ;
2632 
2633 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
2634 
2644 double vpDot2::getSurface() const
2645 {
2646  return fabs(surface);
2647 }
2648 
2660 void vpDot2::setSurface( const double & s )
2661 {
2662  this->surface = s;
2663 }
2664 #endif
virtual void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1)=0
#define vpDEBUG_TRACE
Definition: vpDebug.h:482
double getWidth() const
Definition: vpDot2.cpp:648
Definition of the vpMatrix class.
Definition: vpMatrix.h:98
double m02
Definition: vpDot2.h:414
double getTop() const
Definition: vpRect.h:174
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:347
static bool loadMatrix(std::string filename, vpMatrix &M, const bool binary=false, char *Header=NULL)
Definition: vpMatrix.h:262
double get_v() const
Definition: vpImagePoint.h:263
void searchDotsInArea(const vpImage< unsigned char > &I, int area_u, int area_v, unsigned int area_w, unsigned int area_h, std::list< vpDot2 > &niceDots)
Definition: vpDot2.cpp:1045
void getFreemanChain(std::list< unsigned int > &freeman_chain) const
Definition: vpDot2.cpp:1632
double mu02
Definition: vpDot2.h:433
double get_i() const
Definition: vpImagePoint.h:194
unsigned int getWidth() const
Definition: vpImage.h:159
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:892
#define vpERROR_TRACE
Definition: vpDebug.h:395
#define vpTRACE
Definition: vpDebug.h:418
vp_deprecated double getSurface() const
Definition: vpDot2.cpp:2644
Class to define colors available for display functionnalities.
Definition: vpColor.h:125
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:288
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:678
vpDot2 & operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:158
double get_u() const
Definition: vpImagePoint.h:252
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:257
double m11
Definition: vpDot2.h:398
double getHeight() const
Definition: vpDot2.cpp:658
double getArea() const
Definition: vpDot2.cpp:668
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:700
double getRight() const
Definition: vpRect.h:167
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:717
static const vpColor green
Definition: vpColor.h:170
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:127
double m01
Definition: vpDot2.h:390
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:465
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1994
double get_j() const
Definition: vpImagePoint.h:205
double getSizePrecision() const
Definition: vpDot2.cpp:688
vp_deprecated void setSurface(const double &surface)
Definition: vpDot2.cpp:2660
static const vpColor red
Definition: vpColor.h:167
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:69
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:137
vpImagePoint getCog() const
Definition: vpDot2.h:163
void setGraphicsThickness(unsigned int t)
Definition: vpDot2.h:318
static bool checkFilename(const char *filename)
Definition: vpIoTools.cpp:485
double getBottom() const
Definition: vpRect.h:103
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:788
Error that can be emited by the vpTracker class and its derivates.
double mu11
Definition: vpDot2.h:423
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:710
void set_u(const double u)
Definition: vpImagePoint.h:216
double m20
Definition: vpDot2.h:405
static double sqr(double x)
Definition: vpMath.h:106
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:206
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1) const
Definition: vpDot2.cpp:223
void set_v(const double v)
Definition: vpImagePoint.h:227
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:212
void setComputeMoments(const bool activate)
Definition: vpDot2.h:274
void setArea(const double &area)
Definition: vpDot2.cpp:767
virtual void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)=0
vpDot2()
Definition: vpDot2.cpp:108
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:863
virtual void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)=0
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:331
void setWidth(const double &width)
Definition: vpDot2.cpp:738
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:2545
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:818
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:266
void setHeight(const double &height)
Definition: vpDot2.cpp:753
double m10
Definition: vpDot2.h:382
unsigned int getHeight() const
Definition: vpImage.h:150
void set_uv(const double u, const double v)
Definition: vpImagePoint.h:238
double mu20
Definition: vpDot2.h:428
Defines a rectangle in the plane.
Definition: vpRect.h:85
double getMeanGrayLevel() const
Definition: vpDot2.h:230
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
double m00
Definition: vpDot2.h:374
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:161
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:220
static const vpColor purple
Definition: vpColor.h:178
void setRect(double l, double t, double w, double h)
Definition: vpRect.h:246
double getLeft() const
Definition: vpRect.h:161
static vpMatrix defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage< unsigned char > &I, vpColor col=vpColor::blue, bool trackDot=true)
Definition: vpDot2.cpp:2438
void setGraphics(const bool activate)
Definition: vpDot2.h:312
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
virtual ~vpDot2()
Definition: vpDot2.cpp:208
static const vpColor blue
Definition: vpColor.h:173
static bool saveMatrix(std::string filename, const vpMatrix &M, const bool binary=false, const char *Header="")
Definition: vpMatrix.h:283