ViSP  2.8.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 - 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  * 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 
94  bbox_u_min = bbox_u_max = bbox_v_min = bbox_v_max = 0;
95 
96  firstBorder_u = 0;
97  firstBorder_v = 0;
98 
99  compute_moment = false ;
100  graphics = false;
101  thickness = 1;
102 }
103 
108 {
109  init();
110 }
111 
121 {
122  init() ;
123 
124  cog = ip;
125 }
126 
130 vpDot2::vpDot2(const vpDot2& twinDot ) : vpTracker()
131 {
132  *this = twinDot;
133 }
134 
138 void vpDot2::operator=(const vpDot2& twinDot )
139 {
140  cog = twinDot.cog;
141 
142  width = twinDot.width;
143  height = twinDot.height;
144  surface = twinDot.surface;
145  gray_level_min = twinDot.gray_level_min;
146  gray_level_max = twinDot.gray_level_max;
147  mean_gray_level = twinDot.mean_gray_level;
148  grayLevelPrecision = twinDot.grayLevelPrecision;
149  gamma = twinDot.gamma; ;
150  sizePrecision = twinDot.sizePrecision;
151  ellipsoidShapePrecision = twinDot.ellipsoidShapePrecision ;
152  maxSizeSearchDistancePrecision = twinDot.maxSizeSearchDistancePrecision;
153  allowedBadPointsPercentage_ = twinDot.allowedBadPointsPercentage_;
154  area = twinDot.area;
155 
156  direction_list = twinDot.direction_list;
157  ip_edges_list = twinDot.ip_edges_list;
158 
159  compute_moment = twinDot.compute_moment;
160  graphics = twinDot.graphics;
161  thickness = twinDot.thickness;
162 
163  bbox_u_min = twinDot.bbox_u_min;
164  bbox_u_max = twinDot.bbox_u_max;
165  bbox_v_min = twinDot.bbox_v_min;
166  bbox_v_max = twinDot.bbox_v_max;
167 
168  firstBorder_u = twinDot.firstBorder_u;
169  firstBorder_v = twinDot.firstBorder_v;
170 
171  m00 = twinDot.m00;
172  m01 = twinDot.m01;
173  m11 = twinDot.m11;
174  m10 = twinDot.m10;
175  m02 = twinDot.m02;
176  m20 = twinDot.m20;
177 
178  mu11 = twinDot.mu11;
179  mu20 = twinDot.mu20;
180  mu02 = twinDot.mu02;
181 }
182 
187 
188 
189 /******************************************************************************
190  *
191  * PUBLIC METHODS
192  *****************************************************************************/
193 
202  unsigned int thickness)
203 {
204  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
205  std::list<vpImagePoint>::const_iterator it;
206 
207  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it)
208  {
209  vpDisplay::displayPoint(I, *it, color);
210  }
211 }
212 
213 
245 void vpDot2::initTracking(const vpImage<unsigned char>& I, unsigned int size)
246 {
247  while ( vpDisplay::getClick(I, cog) != true) ;
248 
249  unsigned int i = (unsigned int)cog.get_i();
250  unsigned int j = (unsigned int)cog.get_j();
251 
252  double Ip = pow((double)I[i][j]/255,1/gamma);
253 
254  if(Ip - (1 - grayLevelPrecision)<0){
255  gray_level_min = 0 ;
256  }
257  else{
258  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
259  if (gray_level_min > 255)
260  gray_level_min = 255;
261  }
262  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
263  if (gray_level_max > 255)
264  gray_level_max = 255;
265 
266  setWidth(size);
267  setHeight(size);
268 
269  try {
270  track( I );
271  }
272  catch(...)
273  {
274  vpERROR_TRACE("Error caught") ;
275  throw ;
276  }
277 }
278 
307  const vpImagePoint &ip, unsigned int size)
308 {
309  cog = ip ;
310 
311  unsigned int i = (unsigned int)cog.get_i();
312  unsigned int j = (unsigned int)cog.get_j();
313 
314  double Ip = pow((double)I[i][j]/255,1/gamma);
315 
316  if(Ip - (1 - grayLevelPrecision)<0){
317  gray_level_min = 0 ;
318  }
319  else{
320  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
321  if (gray_level_min > 255)
322  gray_level_min = 255;
323  }
324  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
325  if (gray_level_max > 255)
326  gray_level_max = 255;
327 
328  setWidth(size);
329  setHeight(size);
330 
331  try {
332  track( I );
333  }
334  catch(...)
335  {
336  vpERROR_TRACE("Error caught") ;
337  throw ;
338  }
339 }
340 
381  const vpImagePoint &ip,
382  unsigned int gray_level_min,
383  unsigned int gray_level_max,
384  unsigned int size)
385 {
386  cog = ip ;
387 
388  this->gray_level_min = gray_level_min;
389  this->gray_level_max = gray_level_max;
390 
391  setWidth(size);
392  setHeight(size);
393 
394  try {
395  track( I );
396  }
397  catch(...)
398  {
399  vpERROR_TRACE("Error caught") ;
400  throw ;
401  }
402 }
403 
404 
405 
445 {
446  m00 = m11 = m02 = m20 = m10 = m01 = 0 ;
447 
448  // First, we will estimate the position of the tracked point
449 
450  // Set the search area to the entire image
451  setArea(I);
452 
453  // create a copy of the dot to search
454  // This copy can be saw as the previous dot used to check if the current one
455  // found with computeParameters() is similar to the previous one (see isValid()
456  // function).
457  // If the found dot is not similar (or valid), we use this copy to set the current
458  // found dot to the previous one (see below).
459  vpDot2 wantedDot(*this);
460 
461  // vpDEBUG_TRACE(0, "Previous dot: ");
462  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
463  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
464  bool found = false;
465  found = computeParameters(I, cog.get_u(), cog.get_v());
466 
467  if (found) {
468  // test if the found dot is valid (ie similar to the previous one)
469  found = isValid( I, wantedDot);
470  if (! found) {
471  *this = wantedDot;
472  //std::cout << "The found dot is not valid" << std::endl;
473  }
474  }
475 
476  if (! found) {
477  // vpDEBUG_TRACE(0, "Search the dot in a biggest window around the last position");
478  // vpDEBUG_TRACE(0, "Bad computed dot: ");
479  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
480  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
481 
482  // if estimation was wrong (get an error tracking), look for the dot
483  // closest from the estimation,
484  // i.e. search for dots in an a region of interest around the this dot and get the first
485  // element in the area.
486 
487  // first get the size of the search window from the dot size
488  double searchWindowWidth, searchWindowHeight;
489  //if( getWidth() == 0 || getHeight() == 0 )
490  if( std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() || std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon() )
491  {
492  searchWindowWidth = 80.;
493  searchWindowHeight = 80.;
494  }
495  else
496  {
497  searchWindowWidth = getWidth() * 5;
498  searchWindowHeight = getHeight() * 5;
499  }
500  std::list<vpDot2> candidates;
501  searchDotsInArea( I,
502  (int)(this->cog.get_u()-searchWindowWidth /2.0),
503  (int)(this->cog.get_v()-searchWindowHeight/2.0),
504  (unsigned int)searchWindowWidth,
505  (unsigned int)searchWindowHeight,
506  candidates);
507 
508  // if the vector is empty, that mean we didn't find any candidate
509  // in the area, return an error tracking.
510  if( candidates.empty() )
511  {
512  vpERROR_TRACE("No dot was found") ;
514  "No dot was found")) ;
515  }
516 
517  // otherwise we've got our dot, update this dot's parameters
518  vpDot2 movingDot = candidates.front();
519 
520  setCog( movingDot.getCog() );
521  setArea( movingDot.getArea() );
522  setWidth( movingDot.getWidth() );
523  setHeight( movingDot.getHeight() );
524 
525  // Update the moments
526  m00 = movingDot.m00;
527  m01 = movingDot.m01;
528  m10 = movingDot.m10;
529  m11 = movingDot.m11;
530  m20 = movingDot.m20;
531  m02 = movingDot.m02;
532 
533  // Update the bounding box
534  bbox_u_min = movingDot.bbox_u_min;
535  bbox_u_max = movingDot.bbox_u_max;
536  bbox_v_min = movingDot.bbox_v_min;
537  bbox_v_max = movingDot.bbox_v_max;
538  }
539  // else {
540  // // test if the found dot is valid,
541  // if( ! isValid( I, wantedDot ) ) {
542  // *this = wantedDot;
543  // vpERROR_TRACE("The found dot is invalid:",
544  // "- could be a problem of size (width or height) or "
545  // " surface (number of pixels) which differ too much "
546  // " to the previous one "
547  // "- or a problem of the shape which is not ellipsoid if "
548  // " use setEllipsoidShapePrecision(double ellipsoidShapePrecision) "
549  // " which is the default case. "
550  // " To track a non ellipsoid shape use setEllipsoidShapePrecision(0)") ;
551  // throw(vpTrackingException(vpTrackingException::featureLostError,
552  // "The found dot is invalid")) ;
553  // }
554  // }
555 
556  // if this dot is partially out of the image, return an error tracking.
557  if( !isInImage( I ) )
558  {
559  vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
561  "No dot was found")) ;
562  }
563 
564  // Get dots center of gravity
565  // unsigned int u = (unsigned int) this->cog.get_u();
566  // unsigned int v = (unsigned int) this->cog.get_v();
567  // Updates the min and max gray levels for the next iteration
568  // double Ip = pow((double)I[v][u]/255,1/gamma);
569  double Ip = pow(getMeanGrayLevel()/255,1/gamma);
570  //printf("current value of gray level center : %i\n", I[v][u]);
571 
572  //getMeanGrayLevel(I);
573  if(Ip - (1 - grayLevelPrecision)<0){
574  gray_level_min = 0 ;
575  }
576  else{
577  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
578  if (gray_level_min > 255)
579  gray_level_min = 255;
580  }
581  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
582  if (gray_level_max > 255)
583  gray_level_max = 255;
584 
585  //printf("%i %i \n",gray_level_max,gray_level_min);
586  if (graphics) {
587  // display a red cross at the center of gravity's location in the image.
588 
589  vpDisplay::displayCross(I, this->cog, 3*thickness+8, vpColor::red, thickness);
590  //vpDisplay::flush(I);
591  }
592 }
593 
612 void
614 {
615  track(I);
616 
617  cog = this->cog;
618 }
619 
621 
627 double vpDot2::getWidth() const
628 {
629  return width;
630 }
631 
637 double vpDot2::getHeight() const
638 {
639  return height;
640 }
641 
652 double vpDot2::getSurface() const
653 {
654  return fabs(surface);
655 }
661 double vpDot2::getArea() const
662 {
663  return fabs(surface);
664 }
665 
672 {
673  return grayLevelPrecision;
674 }
675 
682 {
683  return sizePrecision;
684 }
685 
694 {
695  return ellipsoidShapePrecision;
696 }
697 
704  return maxSizeSearchDistancePrecision;
705 }
706 
710 double vpDot2::getDistance( const vpDot2& distantDot ) const
711 {
712  vpImagePoint cogDistantDot = distantDot.getCog();
713  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
714  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
715  return sqrt( diff_u*diff_u + diff_v*diff_v );
716 }
717 
718 
720 
721 
731 void vpDot2::setWidth( const double & width )
732 {
733  this->width = width;
734 }
735 
746 void vpDot2::setHeight( const double & height )
747 {
748  this->height = height;
749 }
750 
762 void vpDot2::setSurface( const double & surface )
763 {
764  this->surface = surface;
765 }
775 void vpDot2::setArea( const double & area )
776 {
777  this->surface = area;
778 }
779 
796 void vpDot2::setGrayLevelPrecision( const double & grayLevelPrecision )
797 {
798  double epsilon = 0.05;
799  if( grayLevelPrecision<epsilon )
800  {
801  this->grayLevelPrecision = epsilon;
802  }
803  else if( grayLevelPrecision>1 )
804  {
805  this->grayLevelPrecision = 1.0;
806  }
807  else
808  {
809  this->grayLevelPrecision = grayLevelPrecision;
810  }
811 }
826 void vpDot2::setSizePrecision( const double & sizePrecision )
827 {
828  if( sizePrecision<0 )
829  {
830  this->sizePrecision = 0;
831  }
832  else if( sizePrecision>1 )
833  {
834  this->sizePrecision = 1.0;
835  }
836  else
837  {
838  this->sizePrecision = sizePrecision;
839  }
840 }
841 
871 void vpDot2::setEllipsoidShapePrecision(const double & ellipsoidShapePrecision) {
872 
873  if( ellipsoidShapePrecision<0 )
874  {
875  this->ellipsoidShapePrecision = 0;
876  }
877  else if( ellipsoidShapePrecision>1 )
878  {
879  this->ellipsoidShapePrecision = 1.0;
880  }
881  else
882  {
883  this->ellipsoidShapePrecision = ellipsoidShapePrecision;
884  }
885 }
886 
900 void vpDot2::setMaxSizeSearchDistancePrecision( const double & maxSizeSearchDistancePrecision )
901 {
902  double epsilon = 0.05;
903  if( maxSizeSearchDistancePrecision<epsilon )
904  {
905  this-> maxSizeSearchDistancePrecision = epsilon;
906  }
907  else if( maxSizeSearchDistancePrecision >1 )
908  {
909  this->maxSizeSearchDistancePrecision = 1.0;
910  }
911  else
912  {
913  this->maxSizeSearchDistancePrecision = maxSizeSearchDistancePrecision;
914  }
915 }
916 
925 void
927 {
928  setArea(I, 0, 0, I.getWidth(), I.getHeight());
929 }
930 
943 void
945  int u, int v,
946  unsigned int w, unsigned int h)
947 {
948  unsigned int image_w = I.getWidth();
949  unsigned int image_h = I.getHeight();
950 
951  // Bounds the area to the image
952  if (u < 0) u = 0;
953  else if (u >= (int)image_w) u = (int)image_w - 1;
954  if (v < 0) v = 0;
955  else if (v >= (int)image_h) v = (int)image_h - 1;
956 
957  if (((unsigned int)u + w) > image_w) w = image_w - (unsigned int)u - 1;
958  if (((unsigned int)v + h) > image_h) h = image_h - (unsigned int)v - 1;
959 
960  area.setRect(u, v, w, h);
961 }
962 
970 void
971  vpDot2::setArea(const vpRect & a)
972 {
973  area = a;
974 }
975 
977 
978 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
979 
1034 {
1035  vpList<vpDot2>* niceDotsVector = new vpList<vpDot2>();
1036 
1037  // To avoid a warning due to the usage of the following deprecated function
1038  // we duplicate the code
1039  {
1040  // niceDotsVector = searchDotsInArea( I, 0, 0, I.getWidth(), I.getHeight());
1041  }
1042  {
1043  // Fit the input area in the image; we keep only the common part between this
1044  // area and the image.
1045  int area_u = 0;
1046  int area_v = 0;
1047  unsigned int area_w = I.getWidth();
1048  unsigned int area_h = I.getHeight();
1049  setArea(I, area_u, area_v, area_w, area_h);
1050 
1051  // compute the size of the search grid
1052  unsigned int gridWidth;
1053  unsigned int gridHeight;
1054  getGridSize( gridWidth, gridHeight );
1055 
1056  if (graphics) {
1057  // Display the area were the dot is search
1058  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
1059  //vpDisplay::flush(I);
1060  }
1061 
1062  // start the search loop; for all points of the search grid,
1063  // test if the pixel belongs to a valid dot.
1064  // if it is so eventually add it to the vector of valid dots.
1065  // vpList<vpDot2>* niceDotsVector = new vpList<vpDot2>();
1066  vpList<vpDot2>* badDotsVector = new vpList<vpDot2>();
1067 
1068  vpDot2* dotToTest = NULL;
1069  vpDot2 tmpDot;
1070 
1071  unsigned int area_u_min = (unsigned int) area.getLeft();
1072  unsigned int area_u_max = (unsigned int) area.getRight();
1073  unsigned int area_v_min = (unsigned int) area.getTop();
1074  unsigned int area_v_max = (unsigned int) area.getBottom();
1075 
1076  unsigned int u, v;
1077  vpImagePoint cogTmpDot;
1078 
1079  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1080  {
1081  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1082  {
1083  // if the pixel we're in doesn't have the right color (outside the
1084  // graylevel interval), no need to check futher, just get to the
1085  // next grid intersection.
1086  if( !hasGoodLevel(I, u, v) ) continue;
1087 
1088  // Test if an other germ is inside the bounding box of a dot previously
1089  // detected
1090  bool good_germ = true;
1091  niceDotsVector->front();
1092  while( !niceDotsVector->outside() && good_germ == true) {
1093  tmpDot = niceDotsVector->value();
1094 
1095  cogTmpDot = tmpDot.getCog();
1096  double u0 = cogTmpDot.get_u();
1097  double v0 = cogTmpDot.get_v();
1098  double half_w = tmpDot.getWidth() / 2.;
1099  double half_h = tmpDot.getHeight() / 2.;
1100 
1101  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1102  v >= (v0-half_h) && v <= (v0+half_h) ) {
1103  // Germ is in a previously detected dot
1104  good_germ = false;
1105  }
1106  niceDotsVector->next();
1107  }
1108 
1109  if (! good_germ)
1110  continue;
1111 
1112  // Compute the right border position for this possible germ
1113  unsigned int border_u;
1114  unsigned int border_v;
1115  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1116  // germ is not good.
1117  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1118  u = border_u;
1119  v = border_v;
1120  continue;
1121  }
1122 
1123  badDotsVector->front();
1124  #define vpBAD_DOT_VALUE (badDotsVector->value())
1125  vpImagePoint cogBadDot;
1126 
1127  std::list<vpImagePoint>::const_iterator it_edges;
1128  while( !badDotsVector->outside() && good_germ == true)
1129  {
1130  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1131  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1132  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1133  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max)
1134  {
1135 
1136  it_edges = ip_edges_list.begin();
1137  while (it_edges != ip_edges_list.end() && good_germ == true)
1138  {
1139  // Test if the germ belong to a previously detected dot:
1140  // - from the germ go right to the border and compare this
1141  // position to the list of pixels of previously detected dots
1142  cogBadDot = *it_edges;
1143  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1144  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() )
1145  &&
1146  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() ))
1147  {
1148  good_germ = false;
1149  }
1150  ++ it_edges;
1151  }
1152  }
1153  badDotsVector->next();
1154  }
1155  #undef vpBAD_DOT_VALUE
1156 
1157  if (! good_germ) {
1158  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1159  u = border_u;
1160  v = border_v;
1161  continue;
1162  }
1163 
1164  vpTRACE(4, "Try germ (%d, %d)", u, v);
1165 
1166  vpImagePoint germ;
1167  germ.set_u( u );
1168  germ.set_v( v );
1169 
1170  // otherwise estimate the width, height and surface of the dot we
1171  // created, and test it.
1172  if( dotToTest != NULL ) delete dotToTest;
1173  dotToTest = getInstance();
1174  dotToTest->setCog( germ );
1175  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1176  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1177  dotToTest->setGrayLevelPrecision( getGrayLevelPrecision() );
1178  dotToTest->setSizePrecision( getSizePrecision() );
1179  dotToTest->setGraphics( graphics );
1180  dotToTest->setGraphicsThickness( thickness );
1181  dotToTest->setComputeMoments( true );
1182  dotToTest->setArea( area );
1183  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1184 
1185  // first compute the parameters of the dot.
1186  // if for some reasons this caused an error tracking
1187  // (dot partially out of the image...), check the next intersection
1188  if( dotToTest->computeParameters( I ) == false ) {
1189  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1190  u = border_u;
1191  v = border_v;
1192  continue;
1193  }
1194  // if the dot to test is valid,
1195  if( dotToTest->isValid( I, *this ) )
1196  {
1197  vpImagePoint cogDotToTest = dotToTest->getCog();
1198  // Compute the distance to the center. The center used here is not the
1199  // area center available by area.getCenter(area_center_u,
1200  // area_center_v) but the center of the input area which may be
1201  // partially outside the image.
1202 
1203  double area_center_u = area_u + area_w/2.0 - 0.5;
1204  double area_center_v = area_v + area_h/2.0 - 0.5;
1205 
1206  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1207  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1208  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1209 
1210  bool stopLoop = false;
1211  niceDotsVector->front();
1212 
1213  while( !niceDotsVector->outside() && stopLoop == false )
1214  {
1215  vpDot2 tmpDot = niceDotsVector->value();
1216 
1217  //double epsilon = 0.001; // detecte +sieurs points
1218  double epsilon = 3.0;
1219  // if the center of the dot is the same than the current
1220  // don't add it, test the next point of the grid
1221  cogTmpDot = tmpDot.getCog();
1222 
1223  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1224  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1225  {
1226  stopLoop = true;
1227  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1228  u = border_u;
1229  v = border_v;
1230  continue;
1231  }
1232 
1233  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1234  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1235  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1236  otherDiff_v*otherDiff_v );
1237 
1238 
1239  // if the distance of the curent vector element to the center
1240  // is greater than the distance of this dot to the center,
1241  // then add this dot before the current vector element.
1242  if( otherDist > thisDist )
1243  {
1244  niceDotsVector->addLeft( *dotToTest );
1245  niceDotsVector->next();
1246  stopLoop = true;
1247  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1248  u = border_u;
1249  v = border_v;
1250  continue;
1251  }
1252  niceDotsVector->next();
1253  }
1254  vpTRACE(4, "End while (%d, %d)", u, v);
1255 
1256  // if we reached the end of the vector without finding the dot
1257  // or inserting it, insert it now.
1258  if( niceDotsVector->outside() && stopLoop == false )
1259  {
1260  niceDotsVector->end();
1261  niceDotsVector->addRight( *dotToTest );
1262  }
1263  }
1264  else {
1265  // Store bad dots
1266  badDotsVector->front();
1267  badDotsVector->addRight( *dotToTest );
1268  }
1269  }
1270  }
1271  if( dotToTest != NULL ) delete dotToTest;
1272 
1273  delete badDotsVector;
1274 
1275  //return niceDotsVector;
1276  }
1277 
1278 
1279  return niceDotsVector;
1280 
1281 }
1282 
1306  int area_u,
1307  int area_v,
1308  unsigned int area_w,
1309  unsigned int area_h)
1310 
1311 {
1312  // Fit the input area in the image; we keep only the common part between this
1313  // area and the image.
1314  setArea(I, area_u, area_v, area_w, area_h);
1315 
1316  // compute the size of the search grid
1317  unsigned int gridWidth;
1318  unsigned int gridHeight;
1319  getGridSize( gridWidth, gridHeight );
1320 
1321  if (graphics) {
1322  // Display the area were the dot is search
1323  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
1324  //vpDisplay::flush(I);
1325  }
1326 
1327  // start the search loop; for all points of the search grid,
1328  // test if the pixel belongs to a valid dot.
1329  // if it is so eventually add it to the vector of valid dots.
1330  vpList<vpDot2>* niceDotsVector = new vpList<vpDot2>();
1331  vpList<vpDot2>* badDotsVector = new vpList<vpDot2>();
1332 
1333  vpDot2* dotToTest = NULL;
1334  vpDot2 tmpDot;
1335 
1336  unsigned int area_u_min = (unsigned int) area.getLeft();
1337  unsigned int area_u_max = (unsigned int) area.getRight();
1338  unsigned int area_v_min = (unsigned int) area.getTop();
1339  unsigned int area_v_max = (unsigned int) area.getBottom();
1340 
1341  unsigned int u, v;
1342  vpImagePoint cogTmpDot;
1343 
1344  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1345  {
1346  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1347  {
1348  // if the pixel we're in doesn't have the right color (outside the
1349  // graylevel interval), no need to check futher, just get to the
1350  // next grid intersection.
1351  if( !hasGoodLevel(I, u, v) ) continue;
1352 
1353  // Test if an other germ is inside the bounding box of a dot previoulsy
1354  // detected
1355  bool good_germ = true;
1356  niceDotsVector->front();
1357  while( !niceDotsVector->outside() && good_germ == true) {
1358  tmpDot = niceDotsVector->value();
1359 
1360  cogTmpDot = tmpDot.getCog();
1361  double u0 = cogTmpDot.get_u();
1362  double v0 = cogTmpDot.get_v();
1363  double half_w = tmpDot.getWidth() / 2.;
1364  double half_h = tmpDot.getHeight() / 2.;
1365 
1366  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1367  v >= (v0-half_h) && v <= (v0+half_h) ) {
1368  // Germ is in a previously detected dot
1369  good_germ = false;
1370  }
1371  niceDotsVector->next();
1372  }
1373 
1374  if (! good_germ)
1375  continue;
1376 
1377  // Compute the right border position for this possible germ
1378  unsigned int border_u;
1379  unsigned int border_v;
1380  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1381  // germ is not good.
1382  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1383  u = border_u;
1384  v = border_v;
1385  continue;
1386  }
1387 
1388  badDotsVector->front();
1389 #define vpBAD_DOT_VALUE (badDotsVector->value())
1390  vpImagePoint cogBadDot;
1391 
1392  std::list<vpImagePoint>::const_iterator it_edges;
1393  while( !badDotsVector->outside() && good_germ == true)
1394  {
1395  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1396  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1397  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1398  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max)
1399  {
1400 
1401  it_edges = ip_edges_list.begin();
1402  while (it_edges != ip_edges_list.end() && good_germ == true)
1403  {
1404  // Test if the germ belong to a previously detected dot:
1405  // - from the germ go right to the border and compare this
1406  // position to the list of pixels of previously detected dots
1407  cogBadDot = *it_edges;
1408  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1409  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() )
1410  &&
1411  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() ))
1412  {
1413  good_germ = false;
1414  }
1415  ++ it_edges;
1416  }
1417  }
1418  badDotsVector->next();
1419  }
1420 #undef vpBAD_DOT_VALUE
1421 
1422  if (! good_germ) {
1423  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1424  u = border_u;
1425  v = border_v;
1426  continue;
1427  }
1428 
1429  vpTRACE(4, "Try germ (%d, %d)", u, v);
1430 
1431  vpImagePoint germ;
1432  germ.set_u( u );
1433  germ.set_v( v );
1434 
1435  // otherwise estimate the width, height and surface of the dot we
1436  // created, and test it.
1437  if( dotToTest != NULL ) delete dotToTest;
1438  dotToTest = getInstance();
1439  dotToTest->setCog( germ );
1440  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1441  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1442  dotToTest->setGrayLevelPrecision( getGrayLevelPrecision() );
1443  dotToTest->setSizePrecision( getSizePrecision() );
1444  dotToTest->setGraphics( graphics );
1445  dotToTest->setGraphicsThickness( thickness );
1446  dotToTest->setComputeMoments( true );
1447  dotToTest->setArea( area );
1448  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1449 
1450  // first compute the parameters of the dot.
1451  // if for some reasons this caused an error tracking
1452  // (dot partially out of the image...), check the next intersection
1453  if( dotToTest->computeParameters( I ) == false ) {
1454  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1455  u = border_u;
1456  v = border_v;
1457  continue;
1458  }
1459  // if the dot to test is valid,
1460  if( dotToTest->isValid( I, *this ) )
1461  {
1462  vpImagePoint cogDotToTest = dotToTest->getCog();
1463  // Compute the distance to the center. The center used here is not the
1464  // area center available by area.getCenter(area_center_u,
1465  // area_center_v) but the center of the input area which may be
1466  // partially outside the image.
1467 
1468  double area_center_u = area_u + area_w/2.0 - 0.5;
1469  double area_center_v = area_v + area_h/2.0 - 0.5;
1470 
1471  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1472  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1473  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1474 
1475  bool stopLoop = false;
1476  niceDotsVector->front();
1477 
1478  while( !niceDotsVector->outside() && stopLoop == false )
1479  {
1480  vpDot2 tmpDot = niceDotsVector->value();
1481 
1482  //double epsilon = 0.001; // detecte +sieurs points
1483  double epsilon = 3.0;
1484  // if the center of the dot is the same than the current
1485  // don't add it, test the next point of the grid
1486  cogTmpDot = tmpDot.getCog();
1487 
1488  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1489  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1490  {
1491  stopLoop = true;
1492  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1493  u = border_u;
1494  v = border_v;
1495  continue;
1496  }
1497 
1498  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1499  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1500  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1501  otherDiff_v*otherDiff_v );
1502 
1503 
1504  // if the distance of the curent vector element to the center
1505  // is greater than the distance of this dot to the center,
1506  // then add this dot before the current vector element.
1507  if( otherDist > thisDist )
1508  {
1509  niceDotsVector->addLeft( *dotToTest );
1510  niceDotsVector->next();
1511  stopLoop = true;
1512  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1513  u = border_u;
1514  v = border_v;
1515  continue;
1516  }
1517  niceDotsVector->next();
1518  }
1519  vpTRACE(4, "End while (%d, %d)", u, v);
1520 
1521  // if we reached the end of the vector without finding the dot
1522  // or inserting it, insert it now.
1523  if( niceDotsVector->outside() && stopLoop == false )
1524  {
1525  niceDotsVector->end();
1526  niceDotsVector->addRight( *dotToTest );
1527  }
1528  }
1529  else {
1530  // Store bad dots
1531  badDotsVector->front();
1532  badDotsVector->addRight( *dotToTest );
1533  }
1534  }
1535  }
1536  if( dotToTest != NULL ) delete dotToTest;
1537 
1538  delete badDotsVector;
1539 
1540  return niceDotsVector;
1541 }
1542 #endif // VISP_BUILD_DEPRECATED_FUNCTIONS
1543 
1593 void vpDot2::searchDotsInArea(const vpImage<unsigned char>& I, std::list<vpDot2> &niceDots)
1594 {
1595  searchDotsInArea( I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
1596 }
1597 
1620  int area_u,
1621  int area_v,
1622  unsigned int area_w,
1623  unsigned int area_h,
1624  std::list<vpDot2> &niceDots)
1625 
1626 {
1627  // clear the list of nice dots
1628  niceDots.clear();
1629 
1630  // Fit the input area in the image; we keep only the common part between this
1631  // area and the image.
1632  setArea(I, area_u, area_v, area_w, area_h);
1633 
1634  // compute the size of the search grid
1635  unsigned int gridWidth;
1636  unsigned int gridHeight;
1637  getGridSize( gridWidth, gridHeight );
1638 
1639  if (graphics) {
1640  // Display the area were the dot is search
1641  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
1642  //vpDisplay::flush(I);
1643  }
1644 
1645 #ifdef DEBUG
1647  vpDisplay::flush(I);
1648 #endif
1649  // start the search loop; for all points of the search grid,
1650  // test if the pixel belongs to a valid dot.
1651  // if it is so eventually add it to the vector of valid dots.
1652  std::list<vpDot2> badDotsVector;
1653  std::list<vpDot2>::iterator itnice;
1654  std::list<vpDot2>::iterator itbad;
1655 
1656  vpDot2* dotToTest = NULL;
1657  vpDot2 tmpDot;
1658 
1659  unsigned int area_u_min = (unsigned int) area.getLeft();
1660  unsigned int area_u_max = (unsigned int) area.getRight();
1661  unsigned int area_v_min = (unsigned int) area.getTop();
1662  unsigned int area_v_max = (unsigned int) area.getBottom();
1663 
1664  unsigned int u, v;
1665  vpImagePoint cogTmpDot;
1666 
1667  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1668  {
1669  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1670  {
1671  // if the pixel we're in doesn't have the right color (outside the
1672  // graylevel interval), no need to check further, just get to the
1673  // next grid intersection.
1674  if( !hasGoodLevel(I, u, v) ) continue;
1675 
1676  // Test if an other germ is inside the bounding box of a dot previously
1677  // detected
1678  bool good_germ = true;
1679 
1680  itnice = niceDots.begin();
1681  while( itnice != niceDots.end() && good_germ == true) {
1682  tmpDot = *itnice;
1683 
1684  cogTmpDot = tmpDot.getCog();
1685  double u0 = cogTmpDot.get_u();
1686  double v0 = cogTmpDot.get_v();
1687  double half_w = tmpDot.getWidth() / 2.;
1688  double half_h = tmpDot.getHeight() / 2.;
1689 
1690  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1691  v >= (v0-half_h) && v <= (v0+half_h) ) {
1692  // Germ is in a previously detected dot
1693  good_germ = false;
1694  }
1695  ++ itnice;
1696  }
1697 
1698  if (! good_germ)
1699  continue;
1700 
1701  // Compute the right border position for this possible germ
1702  unsigned int border_u;
1703  unsigned int border_v;
1704  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1705  // germ is not good.
1706  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1707  u = border_u;
1708  v = border_v;
1709  continue;
1710  }
1711 
1712  itbad = badDotsVector.begin();
1713 #define vpBAD_DOT_VALUE (*itbad)
1714  vpImagePoint cogBadDot;
1715 
1716  while( itbad != badDotsVector.end() && good_germ == true) {
1717  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1718  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1719  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1720  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max){
1721  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1722  while (it_edges != ip_edges_list.end() && good_germ == true){
1723  // Test if the germ belong to a previously detected dot:
1724  // - from the germ go right to the border and compare this
1725  // position to the list of pixels of previously detected dots
1726  cogBadDot = *it_edges;
1727  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1728  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() )
1729  &&
1730  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() )) {
1731  good_germ = false;
1732  }
1733  ++ it_edges;
1734  }
1735  }
1736  ++itbad;
1737  }
1738 #undef vpBAD_DOT_VALUE
1739 
1740  if (! good_germ) {
1741  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1742  u = border_u;
1743  v = border_v;
1744  continue;
1745  }
1746 
1747  vpTRACE(4, "Try germ (%d, %d)", u, v);
1748 
1749  vpImagePoint germ;
1750  germ.set_u( u );
1751  germ.set_v( v );
1752 
1753  // otherwise estimate the width, height and surface of the dot we
1754  // created, and test it.
1755  if( dotToTest != NULL ) delete dotToTest;
1756  dotToTest = getInstance();
1757  dotToTest->setCog( germ );
1758  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1759  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1761  dotToTest->setSizePrecision( getSizePrecision() );
1762  dotToTest->setGraphics( graphics );
1763  dotToTest->setGraphicsThickness( thickness );
1764  dotToTest->setComputeMoments( true );
1765  dotToTest->setArea( area );
1766  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1767 
1768  // first compute the parameters of the dot.
1769  // if for some reasons this caused an error tracking
1770  // (dot partially out of the image...), check the next intersection
1771  if( dotToTest->computeParameters( I ) == false ) {
1772  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1773  u = border_u;
1774  v = border_v;
1775  continue;
1776  }
1777  // if the dot to test is valid,
1778  if( dotToTest->isValid( I, *this ) )
1779  {
1780  vpImagePoint cogDotToTest = dotToTest->getCog();
1781  // Compute the distance to the center. The center used here is not the
1782  // area center available by area.getCenter(area_center_u,
1783  // area_center_v) but the center of the input area which may be
1784  // partially outside the image.
1785 
1786  double area_center_u = area_u + area_w/2.0 - 0.5;
1787  double area_center_v = area_v + area_h/2.0 - 0.5;
1788 
1789  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1790  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1791  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1792 
1793  bool stopLoop = false;
1794  itnice = niceDots.begin();
1795 
1796  while( itnice != niceDots.end() && stopLoop == false )
1797  {
1798  vpDot2 tmpDot = *itnice;
1799 
1800  //double epsilon = 0.001; // detecte +sieurs points
1801  double epsilon = 3.0;
1802  // if the center of the dot is the same than the current
1803  // don't add it, test the next point of the grid
1804  cogTmpDot = tmpDot.getCog();
1805 
1806  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1807  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1808  {
1809  stopLoop = true;
1810  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1811  u = border_u;
1812  v = border_v;
1813  continue;
1814  }
1815 
1816  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1817  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1818  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1819  otherDiff_v*otherDiff_v );
1820 
1821 
1822  // if the distance of the curent vector element to the center
1823  // is greater than the distance of this dot to the center,
1824  // then add this dot before the current vector element.
1825  if( otherDist > thisDist )
1826  {
1827  niceDots.insert(itnice, *dotToTest );
1828  ++ itnice;
1829  stopLoop = true;
1830  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1831  u = border_u;
1832  v = border_v;
1833  continue;
1834  }
1835  ++itnice;
1836  }
1837  vpTRACE(4, "End while (%d, %d)", u, v);
1838 
1839  // if we reached the end of the vector without finding the dot
1840  // or inserting it, insert it now.
1841  if( itnice == niceDots.end() && stopLoop == false )
1842  {
1843  niceDots.push_back( *dotToTest );
1844  }
1845  }
1846  else {
1847  // Store bad dots
1848  badDotsVector.push_front( *dotToTest );
1849  }
1850  }
1851  }
1852  if( dotToTest != NULL ) delete dotToTest;
1853 }
1854 
1875 bool vpDot2::isValid(const vpImage<unsigned char>& I, const vpDot2& wantedDot )
1876 {
1877  double sizePrecision = wantedDot.getSizePrecision();
1878  double ellipsoidShapePrecision = wantedDot.getEllipsoidShapePrecision();
1879  double epsilon = 0.001;
1880 
1881  //
1882  // First, check the width, height and surface of the dot. Those parameters
1883  // must be the same.
1884  //
1885  //if ( (wantedDot.getWidth() != 0)
1886  // && (wantedDot.getHeight() != 0)
1887  // && (wantedDot.getArea() != 0) )
1888  if ( (std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon())
1889  &&
1890  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon())
1891  &&
1892  (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon()) )
1893  // if (sizePrecision!=0){
1894  if (std::fabs(sizePrecision) > std::numeric_limits<double>::epsilon()){
1895 #ifdef DEBUG
1896  std::cout << "test size precision......................\n";
1897  std::cout << "wanted dot: " << "w=" << wantedDot.getWidth()
1898  << " h=" << wantedDot.getHeight()
1899  << " s=" << wantedDot.getArea()
1900  << " precision=" << sizePrecision
1901  << " epsilon=" << epsilon << std::endl;
1902  std::cout << "dot found: " << "w=" << getWidth()
1903  << " h=" << getHeight()
1904  << " s=" << getArea() << std::endl;
1905 #endif
1906  if( ( wantedDot.getWidth()*sizePrecision-epsilon < getWidth() ) == false )
1907  {
1908  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1909  cog.get_u(), cog.get_v());
1910 #ifdef DEBUG
1911  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1912 #endif
1913  return false;
1914  }
1915 
1916  if( ( getWidth() < wantedDot.getWidth()/(sizePrecision+epsilon ) )== false )
1917  {
1918  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1919  cog.get_u(), cog.get_v());
1920 #ifdef DEBUG
1921  printf("Bad width %g > %g for dot (%g, %g)\n",
1922  getWidth(), wantedDot.getWidth()/(sizePrecision+epsilon),
1923  cog.get_u(), cog.get_v());
1924 #endif
1925  return false;
1926  }
1927 
1928  if( ( wantedDot.getHeight()*sizePrecision-epsilon < getHeight() ) == false )
1929  {
1930  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1931  cog.get_u(), cog.get_v());
1932 #ifdef DEBUG
1933  printf("Bad height %g > %g for dot (%g, %g)\n",
1934  wantedDot.getHeight()*sizePrecision-epsilon, getHeight(),
1935  cog.get_u(), cog.get_v());
1936 #endif
1937  return false;
1938  }
1939 
1940  if( ( getHeight() < wantedDot.getHeight()/(sizePrecision+epsilon )) == false )
1941  {
1942  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1943  cog.get_u(), cog.get_v());
1944 #ifdef DEBUG
1945  printf("Bad height %g > %g for dot (%g, %g)\n",
1946  getHeight(), wantedDot.getHeight()/(sizePrecision+epsilon),
1947  cog.get_u(), cog.get_v());
1948 #endif
1949  return false;
1950  }
1951 
1952  if( ( wantedDot.getArea()*(sizePrecision*sizePrecision)-epsilon < getArea() ) == false )
1953  {
1954  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1955  cog.get_u(), cog.get_v());
1956 #ifdef DEBUG
1957  printf("Bad surface %g > %g for dot (%g, %g)\n",
1958  wantedDot.getArea()*(sizePrecision*sizePrecision)-epsilon,
1959  getArea(),
1960  cog.get_u(), cog.get_v());
1961 #endif
1962  return false;
1963  }
1964 
1965  if( ( getArea() < wantedDot.getArea()/(sizePrecision*sizePrecision+epsilon )) == false )
1966  {
1967  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1968  cog.get_u(), cog.get_v());
1969 #ifdef DEBUG
1970  printf("Bad surface %g < %g for dot (%g, %g)\n",
1971  getArea(), wantedDot.getArea()/(sizePrecision*sizePrecision+epsilon),
1972  cog.get_u(), cog.get_v());
1973 #endif
1974  return false;
1975  }
1976  }
1977  //
1978  // Now we can proceed to more advanced (and costy) checks.
1979  // First check there is a white (>level) elipse within dot
1980  // Then check the dot is surrounded by a black ellipse.
1981  //
1982  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1983  int nb_bad_points = 0;
1984  int nb_max_bad_points = (int)(nb_point_to_test*allowedBadPointsPercentage_);
1985  double step_angle = 2*M_PI / nb_point_to_test;
1986 
1987  // if (ellipsoidShapePrecision != 0 && compute_moment) {
1988  if (std::fabs(ellipsoidShapePrecision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1989  // std::cout << "test shape precision......................\n";
1990  // See F. Chaumette. Image moments: a general and useful set of features
1991  // for visual servoing. IEEE Trans. on Robotics, 20(4):713-723, Ao�t 2004.
1992 
1993  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1994  // = m11 - m10 * m01 / m00
1995  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1996  // = m20 - m10^2 / m00
1997  // mu02 = m02 - m01^2 / m00
1998  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1999  //
2000  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
2001  //
2002  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
2003 
2004  //we compute parameters of the estimated ellipse
2005  double tmp1 = (m01*m01 -m10*m10)/m00+(m20-m02);
2006  double tmp2 = m11 -m10*m01/m00 ;
2007  double Sqrt = sqrt(tmp1*tmp1 + 4*tmp2*tmp2);
2008  double a1 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 + Sqrt));
2009  double a2 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 - Sqrt));
2010  double alpha = 0.5*atan2(2*(m11*m00-m10*m01),
2011  ((m20-m02)*m00-m10*m10+m01*m01));
2012 
2013  // to be able to track small dots, minorize the ellipsoid radius for the
2014  // inner test
2015  a1 -= 1.0;
2016  a2 -= 1.0;
2017 
2018  double innerCoef = ellipsoidShapePrecision ;
2019  unsigned int u, v;
2020  double cog_u = this->cog.get_u();
2021  double cog_v = this->cog.get_v();
2022 
2023  vpImagePoint ip;
2024  nb_bad_points = 0;
2025  for( double theta = 0. ; theta<2*M_PI ; theta+= step_angle ) {
2026  u = (unsigned int) (cog_u + innerCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
2027  v = (unsigned int) (cog_v + innerCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
2028  if( ! this->hasGoodLevel( I, u, v) ) {
2029  // vpTRACE("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g)",
2030  // u, v, cog_u, cog_v);
2031 #ifdef DEBUG
2032  printf("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
2033  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
2034 #endif
2035  //return false;
2036  nb_bad_points ++;
2037  }
2038  if (graphics) {
2039  for (unsigned int t=0; t< thickness; t++) {
2040  ip.set_u( u + t );
2041  ip.set_v( v );
2043  }
2044  }
2045 #ifdef DEBUG
2047  vpDisplay::flush(I);
2048 #endif
2049  }
2050  if (nb_bad_points > nb_max_bad_points)
2051  {
2052 #ifdef DEBUG
2053  printf("Inner ellipse has %d bad points. Max allowed is %d\n",
2054  nb_bad_points, nb_max_bad_points);
2055 #endif
2056  return false;
2057  }
2058  // to be able to track small dots, maximize the ellipsoid radius for the
2059  // inner test
2060  a1 += 2.0;
2061  a2 += 2.0;
2062 
2063  double outCoef = 2-ellipsoidShapePrecision; //1.6;
2064  nb_bad_points = 0;
2065  for( double theta=0. ; theta<2*M_PI ; theta+= step_angle ) {
2066  u = (unsigned int) (cog_u + outCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
2067  v = (unsigned int) (cog_v + outCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
2068 #ifdef DEBUG
2069  //vpDisplay::displayRectangle(I, area, vpColor::yellow);
2070  vpDisplay::displayCross( I, v, u, 7, vpColor::purple ) ;
2071  vpDisplay::flush(I);
2072 #endif
2073  // If outside the area, continue
2074  if ((double)u < area.getLeft() || (double)u > area.getRight()
2075  || (double)v < area.getTop() || (double)v > area.getBottom()) {
2076  continue;
2077  }
2078  if( ! this->hasReverseLevel( I, u, v ) ) {
2079  // vpTRACE("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g)",
2080  // u, v, cog_u, cog_v);
2081 #ifdef DEBUG
2082  printf("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
2083  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
2084 #endif
2085  nb_bad_points ++;
2086  //return false;
2087  }
2088  if (graphics) {
2089  for(unsigned int t=0; t<thickness; t++) {
2090  ip.set_u( u + t);
2091  ip.set_v( v );
2092 
2094  }
2095  }
2096  }
2097  }
2098  if (nb_bad_points > nb_max_bad_points)
2099  {
2100 #ifdef DEBUG
2101  printf("Outside ellipse has %d bad points. Max allowed is %d\n",
2102  nb_bad_points, nb_max_bad_points);
2103 #endif
2104  return false;
2105  }
2106 
2107  return true;
2108 }
2109 
2110 
2111 
2129 bool vpDot2::hasGoodLevel(const vpImage<unsigned char>& I,
2130  const unsigned int &u,
2131  const unsigned int &v) const
2132 {
2133  if( !isInArea( u, v ) )
2134  return false;
2135 
2136  if( I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
2137  {
2138  return true;
2139  }
2140  else
2141  {
2142  return false;
2143  }
2144 }
2145 
2146 
2159 bool vpDot2::hasReverseLevel(const vpImage<unsigned char>& I,
2160  const unsigned int &u,
2161  const unsigned int &v) const
2162 {
2163 
2164  if( !isInArea( u, v ) )
2165  return false;
2166 
2167  if( I[v][u] < gray_level_min || I[v][u] > gray_level_max)
2168  {
2169  return true;
2170  }
2171  else
2172  {
2173  return false;
2174  }
2175 }
2176 
2177 
2186 vpDot2* vpDot2::getInstance()
2187 {
2188  return new vpDot2();
2189 }
2190 
2191 
2192 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
2193 
2211 {
2212  std::list<unsigned int>::const_iterator it;
2213  freeman_chain.kill();
2214  for (it = direction_list.begin(); it != direction_list.end(); ++it) {
2215  freeman_chain += *it;
2216  }
2217 }
2218 #endif
2219 
2235 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain)
2236 {
2237  freeman_chain = direction_list;
2238 }
2239 
2240 
2241 
2242 /******************************************************************************
2243  *
2244  * PRIVATE METHODS
2245  *
2246  ******************************************************************************/
2247 
2248 
2249 
2281 bool vpDot2::computeParameters(const vpImage<unsigned char> &I,
2282  const double &_u,
2283  const double &_v)
2284 {
2285  direction_list.clear();
2286  ip_edges_list.clear();
2287 
2288  double est_u = _u; // estimated
2289  double est_v = _v;
2290 
2291  // if u has default value, set it to the actual center value
2292  //if( est_u == -1.0 )
2293  if( std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u),1.)*std::numeric_limits<double>::epsilon() )
2294  {
2295  est_u = this->cog.get_u();
2296  }
2297 
2298  // if v has default value, set it to the actual center value
2299  //if( est_v == -1.0 )
2300  if( std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v),1.)*std::numeric_limits<double>::epsilon() )
2301  {
2302  est_v = this->cog.get_v();
2303  }
2304 
2305  // if the estimated position of the dot is out of the image, not need to continue,
2306  // return an error tracking
2307  if( !isInArea( (unsigned int) est_u, (unsigned int) est_v ) )
2308  {
2309  vpDEBUG_TRACE(3, "Initial pixel coordinates (%d, %d) for dot tracking are not in the area",
2310  (int) est_u, (int) est_v) ;
2311  return false;
2312  }
2313 
2314  bbox_u_min = (int)I.getWidth();
2315  bbox_u_max = 0;
2316  bbox_v_min = (int)I.getHeight();
2317  bbox_v_max = 0;
2318 
2319  // if the first point doesn't have the right level then there's no point to
2320  // continue.
2321  if( !hasGoodLevel( I, (unsigned int) est_u, (unsigned int) est_v ) )
2322  {
2323  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates",
2324  (int) est_u, (int) est_v) ;
2325  return false;
2326  }
2327 
2328  // find the border
2329 
2330  if(!findFirstBorder(I, (unsigned int) est_u, (unsigned int) est_v,
2331  this->firstBorder_u, this->firstBorder_v)) {
2332 
2333  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates",
2334  (int) est_u, (int) est_v) ;
2335  return false;
2336  }
2337 
2338  unsigned int dir = 6;
2339 
2340  // Determine the first element of the Freeman chain
2341  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
2342  unsigned int firstDir = dir;
2343 
2344  // if we are now out of the image, return an error tracking
2345  if( !isInArea( this->firstBorder_u, this->firstBorder_v ) )
2346  {
2347  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area",
2348  this->firstBorder_u, this->firstBorder_v);
2349  return false;
2350  }
2351 
2352  // store the new direction and dot border coordinates.
2353  direction_list.push_back( dir );
2354  vpImagePoint ip;
2355  ip.set_u( this->firstBorder_u );
2356  ip.set_v( this->firstBorder_v );
2357 
2358  ip_edges_list.push_back( ip );
2359 
2360  int border_u = (int)this->firstBorder_u;
2361  int border_v = (int)this->firstBorder_v;
2362 
2363  // vpTRACE("-----------------------------------------");
2364  // vpTRACE("first border_u: %d border_v: %d dir: %d",
2365  // this->firstBorder_u, this->firstBorder_v,firstDir);
2366  int du, dv;
2367  float dS, dMu, dMv, dMuv, dMu2, dMv2;
2368  m00 = 0.0;
2369  m10 = 0.0;
2370  m01 = 0.0;
2371  m11 = 0.0;
2372  m20 = 0.0;
2373  m02 = 0.0;
2374  // while we didn't come back to the first point, follow the border
2375  do {
2376  // if it was asked, show the border
2377  if (graphics) {
2378  for(int t=0; t< (int)thickness; t++) {
2379  ip.set_u ( border_u + t);
2380  ip.set_v ( border_v );
2381 
2383  }
2384  //vpDisplay::flush(I);
2385  }
2386 #ifdef DEBUG
2387  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
2388  vpDisplay::flush(I);
2389 #endif
2390  // Determine the increments for the parameters
2391  computeFreemanParameters(border_u, border_v, dir, du, dv,
2392  dS, // surface
2393  dMu, dMv, // first order moments
2394  dMuv, dMu2, dMv2); // second order moment
2395 
2396  // Update the parameters
2397  border_u += du; // Next position on the border
2398  border_v += dv;
2399  m00 += dS; // enclosed area
2400  m10 += dMu; // First order moment along v axis
2401  m01 += dMv; // First order moment along u axis
2402  if (compute_moment) {
2403  m11 += dMuv; // Second order moment
2404  m20 += dMu2; // Second order moment along v axis
2405  m02 += dMv2; // Second order moment along u axis
2406  }
2407  // if we are now out of the image, return an error tracking
2408  if( !isInArea( (unsigned int)border_u, (unsigned int)border_v ) ) {
2409 
2410  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
2411  // Can Occur on a single pixel dot located on the top border
2412  return false;
2413  }
2414 
2415  // store the new direction and dot border coordinates.
2416 
2417  direction_list.push_back( dir );
2418 
2419  ip.set_u( border_u );
2420  ip.set_v( border_v );
2421  ip_edges_list.push_back( ip );
2422 
2423  // vpDisplay::getClick(I);
2424 
2425  // update the extreme point of the dot.
2426  if( border_v < bbox_v_min ) bbox_v_min = border_v;
2427  if( border_v > bbox_v_max ) bbox_v_max = border_v;
2428  if( border_u < bbox_u_min ) bbox_u_min = border_u;
2429  if( border_u > bbox_u_max ) bbox_u_max = border_u;
2430 
2431  // move around the tracked entity by following the border.
2432  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
2433  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)",
2434  border_u, border_v);
2435  return false;
2436  }
2437 
2438  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v, dir);
2439 
2440  }
2441  while( (getFirstBorder_u() != (unsigned int)border_u
2442  || getFirstBorder_v() != (unsigned int)border_v
2443  || firstDir != dir) &&
2444  isInArea( (unsigned int)border_u, (unsigned int)border_v ) );
2445 
2446 #ifdef VP_DEBUG
2447 #if VP_DEBUG_MODE == 3
2448  vpDisplay::flush(I);
2449 #endif
2450 #endif
2451 
2452  // if the surface is one or zero , the center of gravity wasn't properly
2453  // detected. Return an error tracking.
2454  //if( m00 == 0 || m00 == 1 )
2455  if( std::fabs(m00) <= std::numeric_limits<double>::epsilon()
2456  || std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.)*std::numeric_limits<double>::epsilon() )
2457  {
2458  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
2459  return false;
2460  }
2461  else // compute the center
2462  {
2463  // this magic formula gives the coordinates of the center of gravity
2464  double tmpCenter_u = m10 / m00;
2465  double tmpCenter_v = m01 / m00;
2466 
2467  //Updates the central moments
2468  if (compute_moment)
2469  {
2470  mu11 = m11 - tmpCenter_u*m01;
2471  mu02 = m02 - tmpCenter_v*m01;
2472  mu20 = m20 - tmpCenter_u*m10;
2473  }
2474 
2475 
2476  // check the center is in the image... never know...
2477  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
2478  // (unsigned int)tmpCenter_v ) )
2479  // {
2480  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has not a good in level", tmpCenter_u, tmpCenter_v);
2481  // return false;
2482  // }
2483 
2484  cog.set_u( tmpCenter_u );
2485  cog.set_v( tmpCenter_v );
2486  }
2487 
2488  width = bbox_u_max - bbox_u_min + 1;
2489  height = bbox_v_max - bbox_v_min + 1;
2490  surface = m00;
2491 
2492  computeMeanGrayLevel(I);
2493  return true;
2494 }
2495 
2496 
2512 bool
2513  vpDot2::findFirstBorder(const vpImage<unsigned char> &I,
2514  const unsigned int &u,
2515  const unsigned int &v,
2516  unsigned int &border_u,
2517  unsigned int &border_v)
2518 {
2519  // find the border
2520 
2521  // NOTE:
2522  // from here we use int and not double. This is because we don't have
2523  // rounding problems and it's actually more a trouble than smth else to
2524  // work with double when navigating around the dot.
2525  border_u = u;
2526  border_v = v;
2527  double epsilon =0.001;
2528 
2529 #ifdef DEBUG
2530  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
2531 #endif
2532  while( hasGoodLevel( I, border_u+1, border_v ) &&
2533  border_u < area.getRight()/*I.getWidth()*/ ) {
2534  // if the width of this dot was initialised and we already crossed the dot
2535  // on more than the max possible width, no need to continue, return an
2536  // error tracking
2537  if( getWidth() > 0 && ( border_u - u ) > getWidth()/(getMaxSizeSearchDistancePrecision()+epsilon) ) {
2538  vpDEBUG_TRACE(3, "The found dot (%d, %d, %d) has a greater width than the required one", u, v, border_u);
2539  return false;
2540  }
2541 #ifdef DEBUG
2542  vpDisplay::displayPoint(I, border_v, border_u+1, vpColor::green);
2543  vpDisplay::flush(I);
2544 #endif
2545 
2546  border_u++;
2547  }
2548  return true;
2549 }
2550 
2551 
2570 bool
2571  vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I,
2572  const unsigned int &u,
2573  const unsigned int &v,
2574  unsigned int &element)
2575 {
2576 
2577  if (hasGoodLevel( I, u, v )) {
2578  unsigned int _u = u;
2579  unsigned int _v = v;
2580  // get the point on the right of the point passed in
2581  updateFreemanPosition( _u, _v, (element + 2) %8 );
2582  if (hasGoodLevel( I, _u, _v )) {
2583  element = (element + 2) % 8; // turn right
2584  }
2585  else {
2586  unsigned int _u = u;
2587  unsigned int _v = v;
2588  updateFreemanPosition( _u, _v, (element + 1) %8 );
2589 
2590  if ( hasGoodLevel( I, _u, _v )) {
2591  element = (element + 1) % 8; // turn diag right
2592  }
2593  else {
2594  unsigned int _u = u;
2595  unsigned int _v = v;
2596  updateFreemanPosition( _u, _v, element ); // same direction
2597 
2598  if ( hasGoodLevel( I, _u, _v )) {
2599  //element = element; // keep same dir
2600  }
2601  else {
2602  unsigned int _u = u;
2603  unsigned int _v = v;
2604  updateFreemanPosition( _u, _v, (element + 7) %8 ); // diag left
2605 
2606  if ( hasGoodLevel( I, _u, _v )) {
2607  element = (element + 7) %8; // turn diag left
2608  }
2609  else {
2610  unsigned int _u = u;
2611  unsigned int _v = v;
2612  updateFreemanPosition( _u, _v, (element + 6) %8 ); // left
2613 
2614  if ( hasGoodLevel( I, _u, _v )) {
2615  element = (element + 6) %8 ; // turn left
2616  }
2617  else {
2618  unsigned int _u = u;
2619  unsigned int _v = v;
2620  updateFreemanPosition( _u, _v, (element + 5) %8 ); // left
2621 
2622  if ( hasGoodLevel( I, _u, _v )) {
2623  element = (element + 5) %8 ; // turn diag down
2624  }
2625  else {
2626  unsigned int _u = u;
2627  unsigned int _v = v;
2628  updateFreemanPosition( _u, _v, (element + 4) %8 ); // left
2629 
2630  if ( hasGoodLevel( I, _u, _v )) {
2631  element = (element + 4) %8 ; // turn down
2632  }
2633  else {
2634  unsigned int _u = u;
2635  unsigned int _v = v;
2636  updateFreemanPosition( _u, _v, (element + 3) %8 ); // diag
2637 
2638  if ( hasGoodLevel( I, _u, _v )) {
2639  element = (element + 3) %8 ; // turn diag right down
2640  }
2641  else {
2642  // No neighbor with a good level
2643  //
2644  return false;
2645  }
2646  }
2647  }
2648  }
2649  }
2650  }
2651  }
2652  }
2653  }
2654 
2655  else {
2656  return false;
2657  }
2658 
2659  return true;
2660 
2661 }
2662 
2694 void
2695  vpDot2::computeFreemanParameters(const int &u_p,
2696  const int &v_p,
2697  unsigned int &element,
2698  int &du, int &dv,
2699  float &dS,
2700  float &dMu, float &dMv,
2701  float &dMuv,
2702  float &dMu2, float &dMv2)
2703 {
2704  du = 0;
2705  dv = 0;
2706  dMuv = 0;
2707  dMu2 = 0;
2708  dMv2 = 0;
2709 
2710  /*
2711  3 2 1
2712  \ | /
2713  \|/
2714  4 ------- 0
2715  /|\
2716  / | \
2717  5 6 7
2718  */
2719  switch(element) {
2720  case 0: // go right
2721  du = 1;
2722  dS = (float) v_p;
2723  dMu = 0.0;
2724  dMv = (float)(0.5 * v_p * v_p);
2725  if (compute_moment) {
2726  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
2727  dMu2 = 0;
2728  dMv2 = (float)(1.0/ 3. * v_p * v_p * v_p);
2729  }
2730  break;
2731 
2732  case 1: // go right top
2733  du = 1;
2734  dv = 1;
2735  dS = (float)(v_p + 0.5);
2736  dMu = - (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2737  dMv = (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2738  if (compute_moment) {
2739  float half_u_p = (float)(0.5*u_p);
2740  dMuv = (float)(v_p*v_p*(0.25+half_u_p) + v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2741  dMu2 = (float)(-1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1./12.0);
2742  dMv2 = (float)( 1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1./12.0);
2743  }
2744  break;
2745 
2746  case 2: // go top
2747  dv = 1;
2748  dS = 0.0;
2749  dMu = (float)(- 0.5 * u_p * u_p);
2750  dMv = 0.0;
2751  if (compute_moment) {
2752  dMuv = 0;
2753  dMu2 = (float)(-1.0/ 3. * u_p * u_p * u_p);
2754  dMv2 = 0;
2755  }
2756  break;
2757 
2758  case 3:
2759  du = -1;
2760  dv = 1;
2761  dS = (float)(- v_p - 0.5);
2762  dMu = - (float)(0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2763  dMv = - (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2764  if (compute_moment) {
2765  float half_u_p = (float)(0.5*u_p);
2766  dMuv = (float)(v_p*v_p*(0.25-half_u_p) + v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2767  dMu2 = (float)(-1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2768  dMv2 = (float)(-1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1./12.0);
2769  }
2770  break;
2771 
2772  case 4:
2773  du = -1;
2774  dS = (float)(- v_p);
2775  dMv = (float)(- 0.5 * v_p * v_p);
2776  dMu = 0.0;
2777  if (compute_moment) {
2778  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2779  dMu2 = 0;
2780  dMv2 = (float)(-1.0/ 3. * v_p * v_p * v_p);
2781  }
2782  break;
2783 
2784  case 5:
2785  du = -1;
2786  dv = -1;
2787  dS = (float)(- v_p + 0.5);
2788  dMu = (float)( 0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2789  dMv = (float)(- (0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0));
2790  if (compute_moment) {
2791  float half_u_p = (float)(0.5*u_p);
2792  dMuv = (float)(v_p*v_p*(0.25-half_u_p) - v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2793  dMu2 = (float)( 1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2794  dMv2 = (float)(-1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2795  }
2796  break;
2797 
2798  case 6:
2799  dv = -1;
2800  dS = 0.0;
2801  dMu = (float)(0.5 * u_p * u_p);
2802  dMv = 0.0;
2803  if (compute_moment) {
2804  dMuv = 0;
2805  dMu2 = (float)(1.0/ 3. * u_p * u_p * u_p);
2806  dMv2 = 0;
2807  }
2808  break;
2809 
2810  case 7:
2811  du = 1;
2812  dv = -1;
2813  dS = (float)(v_p - 0.5);
2814  dMu = (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2815  dMv = (float)(0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0);
2816  if (compute_moment) {
2817  float half_u_p = (float)(0.5*u_p);
2818  dMuv = (float)(v_p*v_p*(0.25+half_u_p) - v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2819  dMu2 = (float)(1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1./12.0);
2820  dMv2 = (float)(1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2821  }
2822  break;
2823  }
2824 }
2825 
2826 
2840 void vpDot2::updateFreemanPosition( unsigned int& u, unsigned int& v,
2841  const unsigned int &dir )
2842 {
2843  switch(dir) {
2844  case 0: u += 1; break;
2845  case 1: u += 1; v += 1; break;
2846  case 2: v += 1; break;
2847  case 3: u -= 1; v += 1; break;
2848  case 4: u -= 1; break;
2849  case 5: u -= 1; v -= 1; break;
2850  case 6: v -= 1; break;
2851  case 7: u += 1; v -= 1; break;
2852  }
2853 }
2854 
2866 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const
2867 {
2868  return isInImage( I, cog);
2869 }
2870 
2882 bool vpDot2::isInImage(const vpImage<unsigned char> &I,
2883  const vpImagePoint &ip) const
2884 {
2885  unsigned int height = I.getHeight();
2886  unsigned int width = I.getWidth();
2887  double u = ip.get_u();
2888  double v = ip.get_v();
2889 
2890  if( u < 0 || u >= width ) return false;
2891  if( v < 0 || v >= height ) return false;
2892  return true;
2893 }
2894 
2906 bool vpDot2::isInArea( const unsigned int &u, const unsigned int &v) const
2907 {
2908  unsigned int area_u_min = (unsigned int) area.getLeft();
2909  unsigned int area_u_max = (unsigned int) area.getRight();
2910  unsigned int area_v_min = (unsigned int) area.getTop();
2911  unsigned int area_v_max = (unsigned int) area.getBottom();
2912 
2913  if( u < area_u_min || u > area_u_max ) return false;
2914  if( v < area_v_min || v > area_v_max ) return false;
2915  return true;
2916 }
2917 
2918 
2930 void vpDot2::getGridSize( unsigned int &gridWidth, unsigned int &gridHeight )
2931 {
2932  // first get the research grid width and height Note that
2933  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2934  // contained in the dot. We gent this here if the dot is a perfect disc.
2935  // More accurate criterium to define the grid should be implemented if
2936  // necessary
2937  gridWidth = (unsigned int) (getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2938  gridHeight = (unsigned int) (getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2939 
2940  if( gridWidth == 0 ) gridWidth = 1;
2941  if( gridHeight == 0 ) gridHeight = 1;
2942 }
2943 
2944 
2945 
2958 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char>& I)
2959 {
2960  int cog_u = (int)cog.get_u();
2961  int cog_v = (int)cog.get_v();
2962 
2963  unsigned int sum_value =0;
2964  unsigned int nb_pixels =0;
2965 
2966  for(unsigned int i=(unsigned int)this->bbox_u_min; i <=(unsigned int)this->bbox_u_max ; i++){
2967  unsigned int pixel_gray =(unsigned int) I[(unsigned int)cog_v][i];
2968  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2969  sum_value += pixel_gray;
2970  nb_pixels ++;
2971  }
2972  }
2973  for(unsigned int i=(unsigned int)this->bbox_v_min; i <=(unsigned int)this->bbox_v_max ; i++){
2974  unsigned char pixel_gray =I[i][(unsigned int)cog_u];
2975  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2976  sum_value += pixel_gray;
2977  nb_pixels ++;
2978  }
2979  }
2980  if(nb_pixels < 10){ //could be good to choose the min nb points from area of dot
2981  //add diagonals points to have enough point
2982  int imin,imax;
2983  if( (cog_u - bbox_u_min) > (cog_v - bbox_v_min)){
2984  imin=cog_v - bbox_v_min;
2985  }
2986  else{ imin = cog_u - bbox_u_min;}
2987  if( (bbox_u_max - cog_u) > (bbox_v_max - cog_v)){
2988  imax=bbox_v_max - cog_v;
2989  }
2990  else{ imax = bbox_u_max - cog_u;}
2991  for(int i=-imin; i <=imax ; i++){
2992  unsigned int pixel_gray =(unsigned int) I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2993  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2994  sum_value += pixel_gray;
2995  nb_pixels ++;
2996  }
2997  }
2998 
2999  if( (cog_u - bbox_u_min) > (bbox_v_max - cog_v)){
3000  imin = bbox_v_max - cog_v;
3001  }
3002  else{ imin = cog_u - bbox_u_min;}
3003  if( (bbox_u_max - cog_u) > (cog_v - bbox_v_min)){
3004  imax = cog_v - bbox_v_min;
3005  }
3006  else{ imax = bbox_u_max - cog_u;}
3007 
3008  for(int i=-imin; i <=imax ; i++){
3009  unsigned char pixel_gray =I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
3010  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
3011  sum_value += pixel_gray;
3012  nb_pixels ++;
3013  }
3014  }
3015  }
3016 
3017  if(nb_pixels== 0){
3018  //should never happen
3020  }
3021  else{
3022  mean_gray_level = sum_value/nb_pixels;
3023  }
3024 }
3025 
3026 
3042 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I, vpColor col, bool trackDot)
3043 {
3044  vpMatrix Cogs(n, 2);
3045  vpImagePoint cog;
3046  unsigned int i;
3047  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
3048  if(fromFile)
3049  {
3050  vpMatrix::loadMatrix(dotFile, Cogs);
3051  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
3052  }
3053 
3054  // test number of cogs in file
3055  if(Cogs.getRows() < n)
3056  {
3057  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
3058  fromFile = false;
3059  }
3060 
3061  // read from file and tracks the dots
3062  if(fromFile)
3063  {
3064  try
3065  {
3066  for(i=0;i<n;++i)
3067  {
3068  cog.set_uv(Cogs[i][0], Cogs[i][1]);
3069  dot[i].setGraphics(true);
3070  dot[i].setCog(cog);
3071  if(trackDot)
3072  {
3073  dot[i].initTracking(I,cog);
3074  dot[i].track(I);
3075  vpDisplay::displayCross(I, cog, 10, col);
3076  }
3077  }
3078  }
3079  catch(...)
3080  {
3081  std::cout << "Cannot track dots from file" << std::endl;
3082  fromFile = false;
3083  }
3084  vpDisplay::flush(I);
3085 
3086  // check that dots are far away ones from the other
3087  double d;
3088  for(i=0;i<n && fromFile;++i)
3089  {
3090  d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
3091  for(unsigned int j=0;j<n && fromFile;++j)
3092  if(j!=i)
3093  if(dot[i].getDistance(dot[j]) < d)
3094  {
3095  fromFile = false;
3096  std::cout << "Dots from file seem incoherent" << std::endl;
3097  }
3098  }
3099  }
3100 
3101  if(!fromFile)
3102  {
3103  vpDisplay::display(I);
3104  vpDisplay::flush(I);
3105 
3106  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
3107  for (i = 0; i < n; i++)
3108  {
3109  if(trackDot)
3110  {
3111  dot[i].setGraphics(true);
3112  dot[i].initTracking(I);
3113  cog = dot[i].getCog();
3114  }
3115  else
3116  {
3117  vpDisplay::getClick(I, cog);
3118  dot[i].setCog(cog);
3119  }
3120  Cogs[i][0] = cog.get_u();
3121  Cogs[i][1] = cog.get_v();
3122  vpDisplay::displayCross(I, cog, 10, col);
3123  vpDisplay::flush(I);
3124  }
3125  }
3126 
3127  if (!fromFile & (dotFile != ""))
3128  {
3129  vpMatrix::saveMatrix(dotFile, Cogs);
3130  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
3131  }
3132 
3133  // back to non graphic mode
3134  for(i=0;i<n;++i)
3135  dot[i].setGraphics(false);
3136 
3137  return Cogs;
3138 }
3139 
3149 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I, std::vector<vpImagePoint> &cogs, vpImagePoint* cogStar)
3150 {
3151  unsigned int i;
3152  // tracking
3153  for(i=0;i<n;++i)
3154  {
3155  dot[i].track(I);
3156  cogs.push_back(dot[i].getCog());
3157  }
3158  // trajectories
3159  for(i=n;i<cogs.size();++i)
3160  vpDisplay::displayCircle(I,cogs[i],4,vpColor::green,true);
3161  // initial position
3162  for(i=0;i<n;++i)
3163  vpDisplay::displayCircle(I,cogs[i],4,vpColor::blue,true);
3164  // if exists, desired position
3165  if(cogStar != NULL)
3166  for(i=0;i<n;++i)
3167  {
3168  vpDisplay::displayDotLine(I,cogStar[i],dot[i].getCog(),vpColor::red);
3169  vpDisplay::displayCircle(I,cogStar[i],4,vpColor::red,true);
3170  }
3171  vpDisplay::flush(I);
3172 }
3173 
3189  const std::list<vpImagePoint> &edges_list, vpColor color,
3190  unsigned int thickness)
3191 {
3192  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
3193  std::list<vpImagePoint>::const_iterator it;
3194 
3195  for (it = edges_list.begin(); it != edges_list.end(); ++it)
3196  {
3197  vpDisplay::displayPoint(I, *it, color);
3198  }
3199 }
3200 
3216  const std::list<vpImagePoint> &edges_list, vpColor color,
3217  unsigned int thickness)
3218 {
3219  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
3220  std::list<vpImagePoint>::const_iterator it;
3221 
3222  for (it = edges_list.begin(); it != edges_list.end(); ++it)
3223  {
3224  vpDisplay::displayPoint(I, *it, color);
3225  }
3226 }
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:454
double getWidth() const
Definition: vpDot2.cpp:627
Definition of the vpMatrix class.
Definition: vpMatrix.h:96
double m02
Definition: vpDot2.h:407
double getTop() const
Definition: vpRect.h:169
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:347
double get_v() const
Definition: vpImagePoint.h:250
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:1619
double mu02
Definition: vpDot2.h:426
void end(void)
Position the current element on the last element of the list.
Definition: vpList.h:400
double get_i() const
Definition: vpImagePoint.h:181
bool outside(void) const
Test if the current element is outside the list (on the virtual element)
Definition: vpList.h:431
unsigned int getWidth() const
Definition: vpImage.h:159
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:900
#define vpERROR_TRACE
Definition: vpDebug.h:379
void setCog(const vpImagePoint &cog)
Definition: vpDot2.h:257
#define vpTRACE
Definition: vpDebug.h:401
Provide simple list management.
Definition: vpList.h:112
static bool saveMatrix(const char *filename, const vpMatrix &M, const bool binary=false, const char *Header="")
Definition: vpMatrix.cpp:3440
double getSurface() const
Definition: vpDot2.cpp:652
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:671
double get_u() const
Definition: vpImagePoint.h:239
double m11
Definition: vpDot2.h:391
double getHeight() const
Definition: vpDot2.cpp:637
double getArea() const
Definition: vpDot2.cpp:661
void kill()
Destroy the list.
Definition: vpList.h:694
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:693
double getRight() const
Definition: vpRect.h:162
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:710
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:131
double m01
Definition: vpDot2.h:383
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:444
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1991
double get_j() const
Definition: vpImagePoint.h:192
double getSizePrecision() const
Definition: vpDot2.cpp:681
void setSurface(const double &surface)
Definition: vpDot2.cpp:762
void next(void)
position the current element on the next one
Definition: vpList.h:275
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:167
static bool checkFilename(const char *filename)
Definition: vpIoTools.cpp:485
double getBottom() const
Definition: vpRect.h:98
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:796
void setRect(double left, double top, double width, double height)
Definition: vpRect.h:234
Error that can be emited by the vpTracker class and its derivates.
void addLeft(const type &el)
add a new element in the list, at the left of the current one
Definition: vpList.h:513
double mu11
Definition: vpDot2.h:416
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:703
void set_u(const double u)
Definition: vpImagePoint.h:203
double m20
Definition: vpDot2.h:398
static double sqr(double x)
Definition: vpMath.h:106
static bool loadMatrix(const char *filename, vpMatrix &M, const bool binary=false, char *Header=NULL)
Definition: vpMatrix.cpp:3513
void front(void)
Position the current element on the first element of the list.
Definition: vpList.h:386
void getFreemanChain(std::list< unsigned int > &freeman_chain)
Definition: vpDot2.cpp:2235
void operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:138
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:203
type & value(void)
return the value of the current element
Definition: vpList.h:303
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
void addRight(const type &el)
add a new element in the list, at the right of the current one
Definition: vpList.h:480
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:204
void setComputeMoments(const bool activate)
Definition: vpDot2.h:274
void setArea(const double &area)
Definition: vpDot2.cpp:775
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:107
void setGraphicsThickness(unsigned int thickness)
Definition: vpDot2.h:318
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:871
virtual void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)=0
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
Definition: vpDot2.cpp:201
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:331
void setWidth(const double &width)
Definition: vpDot2.cpp:731
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:3149
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:826
double getMeanGrayLevel()
Definition: vpDot2.h:222
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:245
void setHeight(const double &height)
Definition: vpDot2.cpp:746
double m10
Definition: vpDot2.h:375
unsigned int getHeight() const
Definition: vpImage.h:150
void set_uv(const double u, const double v)
Definition: vpImagePoint.h:225
double mu20
Definition: vpDot2.h:421
Defines a rectangle in the plane.
Definition: vpRect.h:82
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:367
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:157
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:212
static const vpColor purple
Definition: vpColor.h:178
double getLeft() const
Definition: vpRect.h:156
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:3042
void setGraphics(const bool activate)
Definition: vpDot2.h:312
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
virtual ~vpDot2()
Definition: vpDot2.cpp:186
static const vpColor blue
Definition: vpColor.h:173