ViSP  2.6.2
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 - 2012 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Track a white dot.
36  *
37  * Authors:
38  * 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
75  vpDot2::init()
76 {
77  cog.set_u(0);
78  cog.set_v(0);
79 
80  width = 0;
81  height = 0;
82  surface = 0;
83  mean_gray_level = 0;
84  gray_level_min = 128;
85  gray_level_max = 255;
86  grayLevelPrecision = 0.80;
87  gamma = 1.5 ;
88 
89  sizePrecision = 0.65;
90  ellipsoidShapePrecision = 0.65;
91  maxSizeSearchDistancePrecision = 0.65;
93  m00 = m11 = m02 = m20 = m10 = m01 = 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 }
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  mean_gray_level = twinDot.mean_gray_level;
146  gray_level_min = twinDot.gray_level_min;
147  gray_level_max = twinDot.gray_level_max;
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  m00 = twinDot.m00;
157  m01 = twinDot.m01;
158  m11 = twinDot.m11;
159  m10 = twinDot.m10;
160  m02 = twinDot.m02;
161  m20 = twinDot.m20;
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  compute_moment = twinDot.compute_moment;
172  graphics = twinDot.graphics;
173 
174  direction_list = twinDot.direction_list;
175  ip_edges_list = twinDot.ip_edges_list;
176 }
177 
182 
183 
184 /******************************************************************************
185  *
186  * PUBLIC METHODS
187  *****************************************************************************/
188 
197  unsigned int thickness)
198 {
199  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
200  std::list<vpImagePoint>::const_iterator it;
201 
202  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it)
203  {
204  vpDisplay::displayPoint(I, *it, color);
205  }
206 }
207 
208 
240 void vpDot2::initTracking(const vpImage<unsigned char>& I, unsigned int size)
241 {
242  while ( vpDisplay::getClick(I, cog) != true) ;
243 
244  unsigned int i = (unsigned int)cog.get_i();
245  unsigned int j = (unsigned int)cog.get_j();
246 
247  double Ip = pow((double)I[i][j]/255,1/gamma);
248 
249  if(Ip - (1 - grayLevelPrecision)<0){
250  gray_level_min = 0 ;
251  }
252  else{
253  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
254  if (gray_level_min > 255)
255  gray_level_min = 255;
256  }
257  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
258  if (gray_level_max > 255)
259  gray_level_max = 255;
260 
261  setWidth(size);
262  setHeight(size);
263 
264  try {
265  track( I );
266  }
267  catch(...)
268  {
269  vpERROR_TRACE("Error caught") ;
270  throw ;
271  }
272 }
273 
302  const vpImagePoint &ip, unsigned int size)
303 {
304  cog = ip ;
305 
306  unsigned int i = (unsigned int)cog.get_i();
307  unsigned int j = (unsigned int)cog.get_j();
308 
309  double Ip = pow((double)I[i][j]/255,1/gamma);
310 
311  if(Ip - (1 - grayLevelPrecision)<0){
312  gray_level_min = 0 ;
313  }
314  else{
315  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
316  if (gray_level_min > 255)
317  gray_level_min = 255;
318  }
319  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
320  if (gray_level_max > 255)
321  gray_level_max = 255;
322 
323  setWidth(size);
324  setHeight(size);
325 
326  try {
327  track( I );
328  }
329  catch(...)
330  {
331  vpERROR_TRACE("Error caught") ;
332  throw ;
333  }
334 }
335 
376  const vpImagePoint &ip,
377  unsigned int gray_level_min,
378  unsigned int gray_level_max,
379  unsigned int size)
380 {
381  cog = ip ;
382 
383  this->gray_level_min = gray_level_min;
384  this->gray_level_max = gray_level_max;
385 
386  setWidth(size);
387  setHeight(size);
388 
389  try {
390  track( I );
391  }
392  catch(...)
393  {
394  vpERROR_TRACE("Error caught") ;
395  throw ;
396  }
397 }
398 
399 
400 
440 {
441  m00 = m11 = m02 = m20 = m10 = m01 = 0 ;
442 
443  // First, we will estimate the position of the tracked point
444 
445  // Set the search area to the entire image
446  setArea(I);
447 
448  // create a copy of the dot to search
449  // This copy can be saw as the previous dot used to check if the current one
450  // found with computeParameters() is similar to the previous one (see isValid()
451  // function).
452  // If the found dot is not similar (or valid), we use this copy to set the current
453  // found dot to the previous one (see below).
454  vpDot2 wantedDot(*this);
455 
456  // vpDEBUG_TRACE(0, "Previous dot: ");
457  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
458  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
459  bool found = false;
460  found = computeParameters(I, cog.get_u(), cog.get_v());
461 
462  if (found) {
463  // test if the found dot is valid (ie similar to the previous one)
464  found = isValid( I, wantedDot);
465  if (! found) {
466  *this = wantedDot;
467  //std::cout << "The found dot is not valid" << std::endl;
468  }
469  }
470 
471  if (! found) {
472  // vpDEBUG_TRACE(0, "Search the dot in a bigest window around the last position");
473  // vpDEBUG_TRACE(0, "Bad computed dot: ");
474  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
475  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
476 
477  // if estimation was wrong (get an error tracking), look for the dot
478  // closest from the estimation,
479  // i.e. search for dots in an area arround the this dot and get the first
480  // element in the area.
481 
482  // first get the size of the search window from the dot size
483  double searchWindowWidth, searchWindowHeight;
484  //if( getWidth() == 0 || getHeight() == 0 )
485  if( std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() || std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon() )
486  {
487  searchWindowWidth = 80.;
488  searchWindowHeight = 80.;
489  }
490  else
491  {
492  searchWindowWidth = getWidth() * 5;
493  searchWindowHeight = getHeight() * 5;
494  }
495  std::list<vpDot2> candidates;
496  searchDotsInArea( I,
497  (int)(this->cog.get_u()-searchWindowWidth /2.0),
498  (int)(this->cog.get_v()-searchWindowHeight/2.0),
499  (unsigned int)searchWindowWidth,
500  (unsigned int)searchWindowHeight,
501  candidates);
502 
503  // if the vector is empty, that mean we didn't find any candidate
504  // in the area, return an error tracking.
505  if( candidates.empty() )
506  {
507  vpERROR_TRACE("No dot was found") ;
509  "No dot was found")) ;
510  }
511 
512  // otherwise we've got our dot, update this dot's parameters
513  vpDot2 movingDot = candidates.front();
514 
515  setCog( movingDot.getCog() );
516  setSurface( movingDot.getSurface() );
517  setWidth( movingDot.getWidth() );
518  setHeight( movingDot.getHeight() );
519 
520  // Update the moments
521  m00 = movingDot.m00;
522  m01 = movingDot.m01;
523  m10 = movingDot.m10;
524  m11 = movingDot.m11;
525  m20 = movingDot.m20;
526  m02 = movingDot.m02;
527 
528  // Update the bounding box
529  bbox_u_min = movingDot.bbox_u_min;
530  bbox_u_max = movingDot.bbox_u_max;
531  bbox_v_min = movingDot.bbox_v_min;
532  bbox_v_max = movingDot.bbox_v_max;
533  }
534  // else {
535  // // test if the found dot is valid,
536  // if( ! isValid( I, wantedDot ) ) {
537  // *this = wantedDot;
538  // vpERROR_TRACE("The found dot is invalid:",
539  // "- could be a problem of size (width or height) or "
540  // " surface (number of pixels) which differ too much "
541  // " to the previous one "
542  // "- or a problem of the shape which is not ellipsoid if "
543  // " use setEllipsoidShapePrecision(double ellipsoidShapePrecision) "
544  // " which is the default case. "
545  // " To track a non ellipsoid shape use setEllipsoidShapePrecision(0)") ;
546  // throw(vpTrackingException(vpTrackingException::featureLostError,
547  // "The found dot is invalid")) ;
548  // }
549  // }
550 
551  // if this dot is partially out of the image, return an error tracking.
552  if( !isInImage( I ) )
553  {
554  vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
556  "No dot was found")) ;
557  }
558 
559  // Get dots center of gravity
560  // unsigned int u = (unsigned int) this->cog.get_u();
561  // unsigned int v = (unsigned int) this->cog.get_v();
562  // Updates the min and max gray levels for the next iteration
563  // double Ip = pow((double)I[v][u]/255,1/gamma);
564  double Ip = pow(getMeanGrayLevel()/255,1/gamma);
565  //printf("current value of gray level center : %i\n", I[v][u]);
566 
567  //getMeanGrayLevel(I);
568  if(Ip - (1 - grayLevelPrecision)<0){
569  gray_level_min = 0 ;
570  }
571  else{
572  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
573  if (gray_level_min > 255)
574  gray_level_min = 255;
575  }
576  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
577  if (gray_level_max > 255)
578  gray_level_max = 255;
579 
580  //printf("%i %i \n",gray_level_max,gray_level_min);
581  if (graphics) {
582  // display a red cross at the center of gravity's location in the image.
583 
584  vpDisplay::displayCross(I, this->cog, 15, vpColor::red);
585  //vpDisplay::flush(I);
586  }
587 }
588 
607 void
609 {
610  track(I);
611 
612  cog = this->cog;
613 }
614 
616 
622 double vpDot2::getWidth() const
623 {
624  return width;
625 }
626 
632 double vpDot2::getHeight() const
633 {
634  return height;
635 }
636 
642 double vpDot2::getSurface() const
643 {
644  return fabs(surface);
645 }
646 
653 {
654  return grayLevelPrecision;
655 }
656 
663 {
664  return sizePrecision;
665 }
666 
675 {
676  return ellipsoidShapePrecision;
677 }
678 
685  return maxSizeSearchDistancePrecision;
686 }
687 
691 double vpDot2::getDistance( const vpDot2& distantDot ) const
692 {
693  vpImagePoint cogDistantDot = distantDot.getCog();
694  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
695  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
696  return sqrt( diff_u*diff_u + diff_v*diff_v );
697 }
698 
699 
701 
702 
712 void vpDot2::setWidth( const double & width )
713 {
714  this->width = width;
715 }
716 
727 void vpDot2::setHeight( const double & height )
728 {
729  this->height = height;
730 }
731 
742 void vpDot2::setSurface( const double & surface )
743 {
744  this->surface = surface;
745 }
746 
763 void vpDot2::setGrayLevelPrecision( const double & grayLevelPrecision )
764 {
765  double epsilon = 0.05;
766  if( grayLevelPrecision<epsilon )
767  {
768  this->grayLevelPrecision = epsilon;
769  }
770  else if( grayLevelPrecision>1 )
771  {
772  this->grayLevelPrecision = 1.0;
773  }
774  else
775  {
776  this->grayLevelPrecision = grayLevelPrecision;
777  }
778 }
793 void vpDot2::setSizePrecision( const double & sizePrecision )
794 {
795  if( sizePrecision<0 )
796  {
797  this->sizePrecision = 0;
798  }
799  else if( sizePrecision>1 )
800  {
801  this->sizePrecision = 1.0;
802  }
803  else
804  {
805  this->sizePrecision = sizePrecision;
806  }
807 }
808 
838 void vpDot2::setEllipsoidShapePrecision(const double & ellipsoidShapePrecision) {
839 
840  if( ellipsoidShapePrecision<0 )
841  {
842  this->ellipsoidShapePrecision = 0;
843  }
844  else if( ellipsoidShapePrecision>1 )
845  {
846  this->ellipsoidShapePrecision = 1.0;
847  }
848  else
849  {
850  this->ellipsoidShapePrecision = ellipsoidShapePrecision;
851  }
852 }
853 
867 void vpDot2::setMaxSizeSearchDistancePrecision( const double & maxSizeSearchDistancePrecision )
868 {
869  double epsilon = 0.05;
870  if( maxSizeSearchDistancePrecision<epsilon )
871  {
872  this-> maxSizeSearchDistancePrecision = epsilon;
873  }
874  else if( maxSizeSearchDistancePrecision >1 )
875  {
876  this->maxSizeSearchDistancePrecision = 1.0;
877  }
878  else
879  {
880  this->maxSizeSearchDistancePrecision = maxSizeSearchDistancePrecision;
881  }
882 }
883 
892 void
893 vpDot2::setArea(const vpImage<unsigned char> &I)
894 {
895  setArea(I, 0, 0, I.getWidth(), I.getHeight());
896 }
897 
910 void
911 vpDot2::setArea(const vpImage<unsigned char> &I,
912  int u, int v,
913  unsigned int w, unsigned int h)
914 {
915  unsigned int image_w = I.getWidth();
916  unsigned int image_h = I.getHeight();
917 
918  // Bounds the area to the image
919  if (u < 0) u = 0;
920  else if (u >= (int)image_w) u = (int)image_w - 1;
921  if (v < 0) v = 0;
922  else if (v >= (int)image_h) v = (int)image_h - 1;
923 
924  if (((unsigned int)u + w) > image_w) w = image_w - (unsigned int)u - 1;
925  if (((unsigned int)v + h) > image_h) h = image_h - (unsigned int)v - 1;
926 
927  area.setRect(u, v, w, h);
928 }
929 
937 void
938  vpDot2::setArea(const vpRect & a)
939 {
940  area = a;
941 }
942 
944 
945 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
946 
1002 {
1003  vpList<vpDot2>* niceDotsVector = new vpList<vpDot2>();
1004 
1005  // To avoid a warning due to the usage of the following deprecated function
1006  // we duplicate the code
1007  {
1008  // niceDotsVector = searchDotsInArea( I, 0, 0, I.getWidth(), I.getHeight());
1009  }
1010  {
1011  // Fit the input area in the image; we keep only the common part between this
1012  // area and the image.
1013  int area_u = 0;
1014  int area_v = 0;
1015  unsigned int area_w = I.getWidth();
1016  unsigned int area_h = I.getHeight();
1017  setArea(I, area_u, area_v, area_w, area_h);
1018 
1019  // compute the size of the search grid
1020  unsigned int gridWidth;
1021  unsigned int gridHeight;
1022  getGridSize( gridWidth, gridHeight );
1023 
1024  if (graphics) {
1025  // Display the area were the dot is search
1027  //vpDisplay::flush(I);
1028  }
1029 
1030  // start the search loop; for all points of the search grid,
1031  // test if the pixel belongs to a valid dot.
1032  // if it is so eventually add it to the vector of valid dots.
1033  // vpList<vpDot2>* niceDotsVector = new vpList<vpDot2>();
1034  vpList<vpDot2>* badDotsVector = new vpList<vpDot2>();
1035 
1036  vpDot2* dotToTest = NULL;
1037  vpDot2 tmpDot;
1038 
1039  unsigned int area_u_min = (unsigned int) area.getLeft();
1040  unsigned int area_u_max = (unsigned int) area.getRight();
1041  unsigned int area_v_min = (unsigned int) area.getTop();
1042  unsigned int area_v_max = (unsigned int) area.getBottom();
1043 
1044  unsigned int u, v;
1045  vpImagePoint cogTmpDot;
1046 
1047  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1048  {
1049  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1050  {
1051  // if the pixel we're in doesn't have the right color (outside the
1052  // graylevel interval), no need to check futher, just get to the
1053  // next grid intersection.
1054  if( !hasGoodLevel(I, u, v) ) continue;
1055 
1056  // Test if an other germ is inside the bounding box of a dot previoulsy
1057  // detected
1058  bool good_germ = true;
1059  niceDotsVector->front();
1060  while( !niceDotsVector->outside() && good_germ == true) {
1061  tmpDot = niceDotsVector->value();
1062 
1063  cogTmpDot = tmpDot.getCog();
1064  double u0 = cogTmpDot.get_u();
1065  double v0 = cogTmpDot.get_v();
1066  double half_w = tmpDot.getWidth() / 2.;
1067  double half_h = tmpDot.getHeight() / 2.;
1068 
1069  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1070  v >= (v0-half_h) && v <= (v0+half_h) ) {
1071  // Germ is in a previously detected dot
1072  good_germ = false;
1073  }
1074  niceDotsVector->next();
1075  }
1076 
1077  if (! good_germ)
1078  continue;
1079 
1080  // Compute the right border position for this possible germ
1081  unsigned int border_u;
1082  unsigned int border_v;
1083  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1084  // germ is not good.
1085  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1086  u = border_u;
1087  v = border_v;
1088  continue;
1089  }
1090 
1091  badDotsVector->front();
1092  #define vpBAD_DOT_VALUE (badDotsVector->value())
1093  vpImagePoint cogBadDot;
1094 
1095  std::list<vpImagePoint>::const_iterator it_edges;
1096  while( !badDotsVector->outside() && good_germ == true)
1097  {
1098  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1099  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1100  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1101  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max)
1102  {
1103 
1104  it_edges = ip_edges_list.begin();
1105  while (it_edges != ip_edges_list.end() && good_germ == true)
1106  {
1107  // Test if the germ belong to a previously detected dot:
1108  // - from the germ go right to the border and compare this
1109  // position to the list of pixels of previously detected dots
1110  cogBadDot = *it_edges;
1111  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1112  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() )
1113  &&
1114  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() ))
1115  {
1116  good_germ = false;
1117  }
1118  ++ it_edges;
1119  }
1120  }
1121  badDotsVector->next();
1122  }
1123  #undef vpBAD_DOT_VALUE
1124 
1125  if (! good_germ) {
1126  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1127  u = border_u;
1128  v = border_v;
1129  continue;
1130  }
1131 
1132  vpTRACE(4, "Try germ (%d, %d)", u, v);
1133 
1134  vpImagePoint germ;
1135  germ.set_u( u );
1136  germ.set_v( v );
1137 
1138  // otherwise estimate the width, height and surface of the dot we
1139  // created, and test it.
1140  if( dotToTest != NULL ) delete dotToTest;
1141  dotToTest = getInstance();
1142  dotToTest->setCog( germ );
1143  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1144  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1145  dotToTest->setGrayLevelPrecision( getGrayLevelPrecision() );
1146  dotToTest->setSizePrecision( getSizePrecision() );
1147  dotToTest->setGraphics( graphics );
1148  dotToTest->setComputeMoments( true );
1149  dotToTest->setArea( area );
1150  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1151 
1152  // first compute the parameters of the dot.
1153  // if for some reasons this caused an error tracking
1154  // (dot partially out of the image...), check the next intersection
1155  if( dotToTest->computeParameters( I ) == false ) {
1156  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1157  u = border_u;
1158  v = border_v;
1159  continue;
1160  }
1161  // if the dot to test is valid,
1162  if( dotToTest->isValid( I, *this ) )
1163  {
1164  vpImagePoint cogDotToTest = dotToTest->getCog();
1165  // Compute the distance to the center. The center used here is not the
1166  // area center available by area.getCenter(area_center_u,
1167  // area_center_v) but the center of the input area which may be
1168  // partially outside the image.
1169 
1170  double area_center_u = area_u + area_w/2.0 - 0.5;
1171  double area_center_v = area_v + area_h/2.0 - 0.5;
1172 
1173  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1174  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1175  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1176 
1177  bool stopLoop = false;
1178  niceDotsVector->front();
1179 
1180  while( !niceDotsVector->outside() && stopLoop == false )
1181  {
1182  vpDot2 tmpDot = niceDotsVector->value();
1183 
1184  //double epsilon = 0.001; // detecte +sieurs points
1185  double epsilon = 3.0;
1186  // if the center of the dot is the same than the current
1187  // don't add it, test the next point of the grid
1188  cogTmpDot = tmpDot.getCog();
1189 
1190  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1191  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1192  {
1193  stopLoop = true;
1194  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1195  u = border_u;
1196  v = border_v;
1197  continue;
1198  }
1199 
1200  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1201  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1202  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1203  otherDiff_v*otherDiff_v );
1204 
1205 
1206  // if the distance of the curent vector element to the center
1207  // is greater than the distance of this dot to the center,
1208  // then add this dot before the current vector element.
1209  if( otherDist > thisDist )
1210  {
1211  niceDotsVector->addLeft( *dotToTest );
1212  niceDotsVector->next();
1213  stopLoop = true;
1214  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1215  u = border_u;
1216  v = border_v;
1217  continue;
1218  }
1219  niceDotsVector->next();
1220  }
1221  vpTRACE(4, "End while (%d, %d)", u, v);
1222 
1223  // if we reached the end of the vector without finding the dot
1224  // or inserting it, insert it now.
1225  if( niceDotsVector->outside() && stopLoop == false )
1226  {
1227  niceDotsVector->end();
1228  niceDotsVector->addRight( *dotToTest );
1229  }
1230  }
1231  else {
1232  // Store bad dots
1233  badDotsVector->front();
1234  badDotsVector->addRight( *dotToTest );
1235  }
1236  }
1237  }
1238  if( dotToTest != NULL ) delete dotToTest;
1239 
1240  delete badDotsVector;
1241 
1242  //return niceDotsVector;
1243  }
1244 
1245 
1246  return niceDotsVector;
1247 
1248 }
1249 
1274  int area_u,
1275  int area_v,
1276  unsigned int area_w,
1277  unsigned int area_h)
1278 
1279 {
1280  // Fit the input area in the image; we keep only the common part between this
1281  // area and the image.
1282  setArea(I, area_u, area_v, area_w, area_h);
1283 
1284  // compute the size of the search grid
1285  unsigned int gridWidth;
1286  unsigned int gridHeight;
1287  getGridSize( gridWidth, gridHeight );
1288 
1289  if (graphics) {
1290  // Display the area were the dot is search
1292  //vpDisplay::flush(I);
1293  }
1294 
1295  // start the search loop; for all points of the search grid,
1296  // test if the pixel belongs to a valid dot.
1297  // if it is so eventually add it to the vector of valid dots.
1298  vpList<vpDot2>* niceDotsVector = new vpList<vpDot2>();
1299  vpList<vpDot2>* badDotsVector = new vpList<vpDot2>();
1300 
1301  vpDot2* dotToTest = NULL;
1302  vpDot2 tmpDot;
1303 
1304  unsigned int area_u_min = (unsigned int) area.getLeft();
1305  unsigned int area_u_max = (unsigned int) area.getRight();
1306  unsigned int area_v_min = (unsigned int) area.getTop();
1307  unsigned int area_v_max = (unsigned int) area.getBottom();
1308 
1309  unsigned int u, v;
1310  vpImagePoint cogTmpDot;
1311 
1312  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1313  {
1314  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1315  {
1316  // if the pixel we're in doesn't have the right color (outside the
1317  // graylevel interval), no need to check futher, just get to the
1318  // next grid intersection.
1319  if( !hasGoodLevel(I, u, v) ) continue;
1320 
1321  // Test if an other germ is inside the bounding box of a dot previoulsy
1322  // detected
1323  bool good_germ = true;
1324  niceDotsVector->front();
1325  while( !niceDotsVector->outside() && good_germ == true) {
1326  tmpDot = niceDotsVector->value();
1327 
1328  cogTmpDot = tmpDot.getCog();
1329  double u0 = cogTmpDot.get_u();
1330  double v0 = cogTmpDot.get_v();
1331  double half_w = tmpDot.getWidth() / 2.;
1332  double half_h = tmpDot.getHeight() / 2.;
1333 
1334  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1335  v >= (v0-half_h) && v <= (v0+half_h) ) {
1336  // Germ is in a previously detected dot
1337  good_germ = false;
1338  }
1339  niceDotsVector->next();
1340  }
1341 
1342  if (! good_germ)
1343  continue;
1344 
1345  // Compute the right border position for this possible germ
1346  unsigned int border_u;
1347  unsigned int border_v;
1348  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1349  // germ is not good.
1350  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1351  u = border_u;
1352  v = border_v;
1353  continue;
1354  }
1355 
1356  badDotsVector->front();
1357 #define vpBAD_DOT_VALUE (badDotsVector->value())
1358  vpImagePoint cogBadDot;
1359 
1360  std::list<vpImagePoint>::const_iterator it_edges;
1361  while( !badDotsVector->outside() && good_germ == true)
1362  {
1363  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1364  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1365  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1366  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max)
1367  {
1368 
1369  it_edges = ip_edges_list.begin();
1370  while (it_edges != ip_edges_list.end() && good_germ == true)
1371  {
1372  // Test if the germ belong to a previously detected dot:
1373  // - from the germ go right to the border and compare this
1374  // position to the list of pixels of previously detected dots
1375  cogBadDot = *it_edges;
1376  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1377  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() )
1378  &&
1379  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() ))
1380  {
1381  good_germ = false;
1382  }
1383  ++ it_edges;
1384  }
1385  }
1386  badDotsVector->next();
1387  }
1388 #undef vpBAD_DOT_VALUE
1389 
1390  if (! good_germ) {
1391  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1392  u = border_u;
1393  v = border_v;
1394  continue;
1395  }
1396 
1397  vpTRACE(4, "Try germ (%d, %d)", u, v);
1398 
1399  vpImagePoint germ;
1400  germ.set_u( u );
1401  germ.set_v( v );
1402 
1403  // otherwise estimate the width, height and surface of the dot we
1404  // created, and test it.
1405  if( dotToTest != NULL ) delete dotToTest;
1406  dotToTest = getInstance();
1407  dotToTest->setCog( germ );
1408  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1409  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1410  dotToTest->setGrayLevelPrecision( getGrayLevelPrecision() );
1411  dotToTest->setSizePrecision( getSizePrecision() );
1412  dotToTest->setGraphics( graphics );
1413  dotToTest->setComputeMoments( true );
1414  dotToTest->setArea( area );
1415  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1416 
1417  // first compute the parameters of the dot.
1418  // if for some reasons this caused an error tracking
1419  // (dot partially out of the image...), check the next intersection
1420  if( dotToTest->computeParameters( I ) == false ) {
1421  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1422  u = border_u;
1423  v = border_v;
1424  continue;
1425  }
1426  // if the dot to test is valid,
1427  if( dotToTest->isValid( I, *this ) )
1428  {
1429  vpImagePoint cogDotToTest = dotToTest->getCog();
1430  // Compute the distance to the center. The center used here is not the
1431  // area center available by area.getCenter(area_center_u,
1432  // area_center_v) but the center of the input area which may be
1433  // partially outside the image.
1434 
1435  double area_center_u = area_u + area_w/2.0 - 0.5;
1436  double area_center_v = area_v + area_h/2.0 - 0.5;
1437 
1438  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1439  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1440  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1441 
1442  bool stopLoop = false;
1443  niceDotsVector->front();
1444 
1445  while( !niceDotsVector->outside() && stopLoop == false )
1446  {
1447  vpDot2 tmpDot = niceDotsVector->value();
1448 
1449  //double epsilon = 0.001; // detecte +sieurs points
1450  double epsilon = 3.0;
1451  // if the center of the dot is the same than the current
1452  // don't add it, test the next point of the grid
1453  cogTmpDot = tmpDot.getCog();
1454 
1455  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1456  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1457  {
1458  stopLoop = true;
1459  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1460  u = border_u;
1461  v = border_v;
1462  continue;
1463  }
1464 
1465  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1466  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1467  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1468  otherDiff_v*otherDiff_v );
1469 
1470 
1471  // if the distance of the curent vector element to the center
1472  // is greater than the distance of this dot to the center,
1473  // then add this dot before the current vector element.
1474  if( otherDist > thisDist )
1475  {
1476  niceDotsVector->addLeft( *dotToTest );
1477  niceDotsVector->next();
1478  stopLoop = true;
1479  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1480  u = border_u;
1481  v = border_v;
1482  continue;
1483  }
1484  niceDotsVector->next();
1485  }
1486  vpTRACE(4, "End while (%d, %d)", u, v);
1487 
1488  // if we reached the end of the vector without finding the dot
1489  // or inserting it, insert it now.
1490  if( niceDotsVector->outside() && stopLoop == false )
1491  {
1492  niceDotsVector->end();
1493  niceDotsVector->addRight( *dotToTest );
1494  }
1495  }
1496  else {
1497  // Store bad dots
1498  badDotsVector->front();
1499  badDotsVector->addRight( *dotToTest );
1500  }
1501  }
1502  }
1503  if( dotToTest != NULL ) delete dotToTest;
1504 
1505  delete badDotsVector;
1506 
1507  return niceDotsVector;
1508 }
1509 #endif // VISP_BUILD_DEPRECATED_FUNCTIONS
1510 
1558 void vpDot2::searchDotsInArea(const vpImage<unsigned char>& I, std::list<vpDot2> &niceDots)
1559 {
1560  searchDotsInArea( I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
1561 }
1562 
1585  int area_u,
1586  int area_v,
1587  unsigned int area_w,
1588  unsigned int area_h,
1589  std::list<vpDot2> &niceDots)
1590 
1591 {
1592  // clear the list of nice dots
1593  niceDots.clear();
1594 
1595  // Fit the input area in the image; we keep only the common part between this
1596  // area and the image.
1597  setArea(I, area_u, area_v, area_w, area_h);
1598 
1599  // compute the size of the search grid
1600  unsigned int gridWidth;
1601  unsigned int gridHeight;
1602  getGridSize( gridWidth, gridHeight );
1603 
1604  if (graphics) {
1605  // Display the area were the dot is search
1607  //vpDisplay::flush(I);
1608  }
1609 
1610 #ifdef DEBUG
1612  vpDisplay::flush(I);
1613 #endif
1614  // start the search loop; for all points of the search grid,
1615  // test if the pixel belongs to a valid dot.
1616  // if it is so eventually add it to the vector of valid dots.
1617  std::list<vpDot2> badDotsVector;
1618  std::list<vpDot2>::iterator itnice;
1619  std::list<vpDot2>::iterator itbad;
1620 
1621  vpDot2* dotToTest = NULL;
1622  vpDot2 tmpDot;
1623 
1624  unsigned int area_u_min = (unsigned int) area.getLeft();
1625  unsigned int area_u_max = (unsigned int) area.getRight();
1626  unsigned int area_v_min = (unsigned int) area.getTop();
1627  unsigned int area_v_max = (unsigned int) area.getBottom();
1628 
1629  unsigned int u, v;
1630  vpImagePoint cogTmpDot;
1631 
1632  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1633  {
1634  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1635  {
1636  // if the pixel we're in doesn't have the right color (outside the
1637  // graylevel interval), no need to check futher, just get to the
1638  // next grid intersection.
1639  if( !hasGoodLevel(I, u, v) ) continue;
1640 
1641  // Test if an other germ is inside the bounding box of a dot previoulsy
1642  // detected
1643  bool good_germ = true;
1644 
1645  itnice = niceDots.begin();
1646  while( itnice != niceDots.end() && good_germ == true) {
1647  tmpDot = *itnice;
1648 
1649  cogTmpDot = tmpDot.getCog();
1650  double u0 = cogTmpDot.get_u();
1651  double v0 = cogTmpDot.get_v();
1652  double half_w = tmpDot.getWidth() / 2.;
1653  double half_h = tmpDot.getHeight() / 2.;
1654 
1655  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1656  v >= (v0-half_h) && v <= (v0+half_h) ) {
1657  // Germ is in a previously detected dot
1658  good_germ = false;
1659  }
1660  ++ itnice;
1661  }
1662 
1663  if (! good_germ)
1664  continue;
1665 
1666  // Compute the right border position for this possible germ
1667  unsigned int border_u;
1668  unsigned int border_v;
1669  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1670  // germ is not good.
1671  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1672  u = border_u;
1673  v = border_v;
1674  continue;
1675  }
1676 
1677  itbad = badDotsVector.begin();
1678 #define vpBAD_DOT_VALUE (*itbad)
1679  vpImagePoint cogBadDot;
1680 
1681  while( itbad != badDotsVector.end() && good_germ == true) {
1682  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1683  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1684  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1685  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max){
1686  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1687  while (it_edges != ip_edges_list.end() && good_germ == true){
1688  // Test if the germ belong to a previously detected dot:
1689  // - from the germ go right to the border and compare this
1690  // position to the list of pixels of previously detected dots
1691  cogBadDot = *it_edges;
1692  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1693  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() )
1694  &&
1695  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() )) {
1696  good_germ = false;
1697  }
1698  ++ it_edges;
1699  }
1700  }
1701  ++itbad;
1702  }
1703 #undef vpBAD_DOT_VALUE
1704 
1705  if (! good_germ) {
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  vpTRACE(4, "Try germ (%d, %d)", u, v);
1713 
1714  vpImagePoint germ;
1715  germ.set_u( u );
1716  germ.set_v( v );
1717 
1718  // otherwise estimate the width, height and surface of the dot we
1719  // created, and test it.
1720  if( dotToTest != NULL ) delete dotToTest;
1721  dotToTest = getInstance();
1722  dotToTest->setCog( germ );
1723  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1724  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1726  dotToTest->setSizePrecision( getSizePrecision() );
1727  dotToTest->setGraphics( graphics );
1728  dotToTest->setComputeMoments( true );
1729  dotToTest->setArea( area );
1730  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1731 
1732  // first compute the parameters of the dot.
1733  // if for some reasons this caused an error tracking
1734  // (dot partially out of the image...), check the next intersection
1735  if( dotToTest->computeParameters( I ) == false ) {
1736  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1737  u = border_u;
1738  v = border_v;
1739  continue;
1740  }
1741  // if the dot to test is valid,
1742  if( dotToTest->isValid( I, *this ) )
1743  {
1744  vpImagePoint cogDotToTest = dotToTest->getCog();
1745  // Compute the distance to the center. The center used here is not the
1746  // area center available by area.getCenter(area_center_u,
1747  // area_center_v) but the center of the input area which may be
1748  // partially outside the image.
1749 
1750  double area_center_u = area_u + area_w/2.0 - 0.5;
1751  double area_center_v = area_v + area_h/2.0 - 0.5;
1752 
1753  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1754  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1755  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1756 
1757  bool stopLoop = false;
1758  itnice = niceDots.begin();
1759 
1760  while( itnice != niceDots.end() && stopLoop == false )
1761  {
1762  vpDot2 tmpDot = *itnice;
1763 
1764  //double epsilon = 0.001; // detecte +sieurs points
1765  double epsilon = 3.0;
1766  // if the center of the dot is the same than the current
1767  // don't add it, test the next point of the grid
1768  cogTmpDot = tmpDot.getCog();
1769 
1770  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1771  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1772  {
1773  stopLoop = true;
1774  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1775  u = border_u;
1776  v = border_v;
1777  continue;
1778  }
1779 
1780  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1781  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1782  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1783  otherDiff_v*otherDiff_v );
1784 
1785 
1786  // if the distance of the curent vector element to the center
1787  // is greater than the distance of this dot to the center,
1788  // then add this dot before the current vector element.
1789  if( otherDist > thisDist )
1790  {
1791  niceDots.insert(itnice, *dotToTest );
1792  ++ itnice;
1793  stopLoop = true;
1794  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1795  u = border_u;
1796  v = border_v;
1797  continue;
1798  }
1799  ++itnice;
1800  }
1801  vpTRACE(4, "End while (%d, %d)", u, v);
1802 
1803  // if we reached the end of the vector without finding the dot
1804  // or inserting it, insert it now.
1805  if( itnice == niceDots.end() && stopLoop == false )
1806  {
1807  niceDots.push_back( *dotToTest );
1808  }
1809  }
1810  else {
1811  // Store bad dots
1812  badDotsVector.push_front( *dotToTest );
1813  }
1814  }
1815  }
1816  if( dotToTest != NULL ) delete dotToTest;
1817 }
1818 
1839 bool vpDot2::isValid(const vpImage<unsigned char>& I, const vpDot2& wantedDot )
1840 {
1841  double sizePrecision = wantedDot.getSizePrecision();
1842  double ellipsoidShapePrecision = wantedDot.getEllipsoidShapePrecision();
1843  double epsilon = 0.001;
1844 
1845  //
1846  // First, check the width, height and surface of the dot. Those parameters
1847  // must be the same.
1848  //
1849  //if ( (wantedDot.getWidth() != 0)
1850  // && (wantedDot.getHeight() != 0)
1851  // && (wantedDot.getSurface() != 0) )
1852  if ( (std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon())
1853  &&
1854  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon())
1855  &&
1856  (std::fabs(wantedDot.getSurface()) > std::numeric_limits<double>::epsilon()) )
1857  // if (sizePrecision!=0){
1858  if (std::fabs(sizePrecision) > std::numeric_limits<double>::epsilon()){
1859 #ifdef DEBUG
1860  std::cout << "test size precision......................\n";
1861  std::cout << "wanted dot: " << "w=" << wantedDot.getWidth()
1862  << " h=" << wantedDot.getHeight()
1863  << " s=" << wantedDot.getSurface()
1864  << " precision=" << sizePrecision
1865  << " epsilon=" << epsilon << std::endl;
1866  std::cout << "dot found: " << "w=" << getWidth()
1867  << " h=" << getHeight()
1868  << " s=" << getSurface() << std::endl;
1869 #endif
1870  if( ( wantedDot.getWidth()*sizePrecision-epsilon < getWidth() ) == false )
1871  {
1872  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1873  cog.get_u(), cog.get_v());
1874 #ifdef DEBUG
1875  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1876 #endif
1877  return false;
1878  }
1879 
1880  if( ( getWidth() < wantedDot.getWidth()/(sizePrecision+epsilon ) )== false )
1881  {
1882  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1883  cog.get_u(), cog.get_v());
1884 #ifdef DEBUG
1885  printf("Bad width %g > %g for dot (%g, %g)\n",
1886  getWidth(), wantedDot.getWidth()/(sizePrecision+epsilon),
1887  cog.get_u(), cog.get_v());
1888 #endif
1889  return false;
1890  }
1891 
1892  if( ( wantedDot.getHeight()*sizePrecision-epsilon < getHeight() ) == false )
1893  {
1894  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1895  cog.get_u(), cog.get_v());
1896 #ifdef DEBUG
1897  printf("Bad height %g > %g for dot (%g, %g)\n",
1898  wantedDot.getHeight()*sizePrecision-epsilon, getHeight(),
1899  cog.get_u(), cog.get_v());
1900 #endif
1901  return false;
1902  }
1903 
1904  if( ( getHeight() < wantedDot.getHeight()/(sizePrecision+epsilon )) == false )
1905  {
1906  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1907  cog.get_u(), cog.get_v());
1908 #ifdef DEBUG
1909  printf("Bad height %g > %g for dot (%g, %g)\n",
1910  getHeight(), wantedDot.getHeight()/(sizePrecision+epsilon),
1911  cog.get_u(), cog.get_v());
1912 #endif
1913  return false;
1914  }
1915 
1916  if( ( wantedDot.getSurface()*(sizePrecision*sizePrecision)-epsilon < getSurface() ) == false )
1917  {
1918  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1919  cog.get_u(), cog.get_v());
1920 #ifdef DEBUG
1921  printf("Bad surface %g > %g for dot (%g, %g)\n",
1922  wantedDot.getSurface()*(sizePrecision*sizePrecision)-epsilon,
1923  getSurface(),
1924  cog.get_u(), cog.get_v());
1925 #endif
1926  return false;
1927  }
1928 
1929  if( ( getSurface() < wantedDot.getSurface()/(sizePrecision*sizePrecision+epsilon )) == false )
1930  {
1931  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1932  cog.get_u(), cog.get_v());
1933 #ifdef DEBUG
1934  printf("Bad surface %g < %g for dot (%g, %g)\n",
1935  getSurface(), wantedDot.getSurface()/(sizePrecision*sizePrecision+epsilon),
1936  cog.get_u(), cog.get_v());
1937 #endif
1938  return false;
1939  }
1940  }
1941  //
1942  // Now we can proceed to more advanced (and costy) checks.
1943  // First check there is a white (>level) elipse within dot
1944  // Then check the dot is surrounded by a black elipse.
1945  //
1946  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1947  int nb_bad_points = 0;
1948  int nb_max_bad_points = (int)(nb_point_to_test*allowedBadPointsPercentage_);
1949  double step_angle = 2*M_PI / nb_point_to_test;
1950 
1951  // if (ellipsoidShapePrecision != 0 && compute_moment) {
1952  if (std::fabs(ellipsoidShapePrecision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1953  // std::cout << "test shape precision......................\n";
1954  // See F. Chaumette. Image moments: a general and useful set of features
1955  // for visual servoing. IEEE Trans. on Robotics, 20(4):713-723, Ao�t 2004.
1956 
1957  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1958  // = m11 - m10 * m01 / m00
1959  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1960  // = m20 - m10^2 / m00
1961  // mu02 = m02 - m01^2 / m00
1962  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1963  //
1964  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1965  //
1966  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1967 
1968  //we compute parameters of the estimated ellipse
1969  double tmp1 = (m01*m01 -m10*m10)/m00+(m20-m02);
1970  double tmp2 = m11 -m10*m01/m00 ;
1971  double Sqrt = sqrt(tmp1*tmp1 + 4*tmp2*tmp2);
1972  double a1 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 + Sqrt));
1973  double a2 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 - Sqrt));
1974  double alpha = 0.5*atan2(2*(m11*m00-m10*m01),
1975  ((m20-m02)*m00-m10*m10+m01*m01));
1976 
1977  // to be able to track small dots, minorize the ellipsoid radius for the
1978  // inner test
1979  a1 -= 1.0;
1980  a2 -= 1.0;
1981 
1982  double innerCoef = ellipsoidShapePrecision ;
1983  unsigned int u, v;
1984  double cog_u = this->cog.get_u();
1985  double cog_v = this->cog.get_v();
1986 
1987  vpImagePoint ip;
1988  nb_bad_points = 0;
1989  for( double theta = 0. ; theta<2*M_PI ; theta+= step_angle ) {
1990  u = (unsigned int) (cog_u + innerCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
1991  v = (unsigned int) (cog_v + innerCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
1992  if( ! this->hasGoodLevel( I, u, v) ) {
1993  // vpTRACE("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g)",
1994  // u, v, cog_u, cog_v);
1995 #ifdef DEBUG
1996  printf("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
1997  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1998 #endif
1999  //return false;
2000  nb_bad_points ++;
2001  }
2002  if (graphics) {
2003  ip.set_u( u );
2004  ip.set_v( v );
2005 
2007  }
2008 #ifdef DEBUG
2010  vpDisplay::flush(I);
2011 #endif
2012  }
2013  if (nb_bad_points > nb_max_bad_points)
2014  {
2015 #ifdef DEBUG
2016  printf("Inner ellipse has %d bad points. Max allowed is %d\n",
2017  nb_bad_points, nb_max_bad_points);
2018 #endif
2019  return false;
2020  }
2021  // to be able to track small dots, maximize the ellipsoid radius for the
2022  // inner test
2023  a1 += 2.0;
2024  a2 += 2.0;
2025 
2026  double outCoef = 2-ellipsoidShapePrecision; //1.6;
2027  nb_bad_points = 0;
2028  for( double theta=0. ; theta<2*M_PI ; theta+= step_angle ) {
2029  u = (unsigned int) (cog_u + outCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
2030  v = (unsigned int) (cog_v + outCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
2031 #ifdef DEBUG
2032  //vpDisplay::displayRectangle(I, area, vpColor::yellow);
2033  vpDisplay::displayCross( I, v, u, 7, vpColor::purple ) ;
2034  vpDisplay::flush(I);
2035 #endif
2036  // If outside the area, continue
2037  if ((double)u < area.getLeft() || (double)u > area.getRight()
2038  || (double)v < area.getTop() || (double)v > area.getBottom()) {
2039  continue;
2040  }
2041  if( ! this->hasReverseLevel( I, u, v ) ) {
2042  // vpTRACE("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g)",
2043  // u, v, cog_u, cog_v);
2044 #ifdef DEBUG
2045  printf("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
2046  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
2047 #endif
2048  nb_bad_points ++;
2049  //return false;
2050  }
2051  if (graphics) {
2052  ip.set_u( u );
2053  ip.set_v( v );
2054 
2056  }
2057  }
2058  }
2059  if (nb_bad_points > nb_max_bad_points)
2060  {
2061 #ifdef DEBUG
2062  printf("Outside ellipse has %d bad points. Max allowed is %d\n",
2063  nb_bad_points, nb_max_bad_points);
2064 #endif
2065  return false;
2066  }
2067 
2068  return true;
2069 }
2070 
2071 
2072 
2090 bool vpDot2::hasGoodLevel(const vpImage<unsigned char>& I,
2091  const unsigned int &u,
2092  const unsigned int &v) const
2093 {
2094  if( !isInArea( u, v ) )
2095  return false;
2096 
2097  if( I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
2098  {
2099  return true;
2100  }
2101  else
2102  {
2103  return false;
2104  }
2105 }
2106 
2107 
2120 bool vpDot2::hasReverseLevel(const vpImage<unsigned char>& I,
2121  const unsigned int &u,
2122  const unsigned int &v) const
2123 {
2124 
2125  if( !isInArea( u, v ) )
2126  return false;
2127 
2128  if( I[v][u] < gray_level_min || I[v][u] > gray_level_max)
2129  {
2130  return true;
2131  }
2132  else
2133  {
2134  return false;
2135  }
2136 }
2137 
2138 
2147 vpDot2* vpDot2::getInstance()
2148 {
2149  return new vpDot2();
2150 }
2151 
2152 
2153 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
2154 
2173 {
2174  std::list<unsigned int>::const_iterator it;
2175  freeman_chain.kill();
2176  for (it = direction_list.begin(); it != direction_list.end(); ++it) {
2177  freeman_chain += *it;
2178  }
2179 }
2180 #endif
2181 
2197 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain)
2198 {
2199  freeman_chain = direction_list;
2200 }
2201 
2202 
2203 
2204 /******************************************************************************
2205  *
2206  * PRIVATE METHODS
2207  *
2208  ******************************************************************************/
2209 
2210 
2211 
2243 bool vpDot2::computeParameters(const vpImage<unsigned char> &I,
2244  const double &_u,
2245  const double &_v)
2246 {
2247  direction_list.clear();
2248  ip_edges_list.clear();
2249 
2250  double est_u = _u; // estimated
2251  double est_v = _v;
2252 
2253  // if u has default value, set it to the actual center value
2254  //if( est_u == -1.0 )
2255  if( std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u),1.)*std::numeric_limits<double>::epsilon() )
2256  {
2257  est_u = this->cog.get_u();
2258  }
2259 
2260  // if v has default value, set it to the actual center value
2261  //if( est_v == -1.0 )
2262  if( std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v),1.)*std::numeric_limits<double>::epsilon() )
2263  {
2264  est_v = this->cog.get_v();
2265  }
2266 
2267  // if the estimated position of the dot is out of the image, not need to continue,
2268  // return an error tracking
2269  if( !isInArea( (unsigned int) est_u, (unsigned int) est_v ) )
2270  {
2271  vpDEBUG_TRACE(3, "Initial pixel coordinates (%d, %d) for dot tracking are not in the area",
2272  (int) est_u, (int) est_v) ;
2273  return false;
2274  }
2275 
2276  bbox_u_min = (int)I.getWidth();
2277  bbox_u_max = 0;
2278  bbox_v_min = (int)I.getHeight();
2279  bbox_v_max = 0;
2280 
2281  // if the first point doesn't have the right level then there's no point to
2282  // continue.
2283  if( !hasGoodLevel( I, (unsigned int) est_u, (unsigned int) est_v ) )
2284  {
2285  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates",
2286  (int) est_u, (int) est_v) ;
2287  return false;
2288  }
2289 
2290  // find the border
2291 
2292  if(!findFirstBorder(I, (unsigned int) est_u, (unsigned int) est_v,
2293  this->firstBorder_u, this->firstBorder_v)) {
2294 
2295  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates",
2296  (int) est_u, (int) est_v) ;
2297  return false;
2298  }
2299 
2300  unsigned int dir = 6;
2301 
2302  // Determine the first element of the Freeman chain
2303  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
2304  unsigned int firstDir = dir;
2305 
2306  // if we are now out of the image, return an error tracking
2307  if( !isInArea( this->firstBorder_u, this->firstBorder_v ) )
2308  {
2309  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area",
2310  this->firstBorder_u, this->firstBorder_v);
2311  return false;
2312  }
2313 
2314  // store the new direction and dot border coordinates.
2315  direction_list.push_back( dir );
2316  vpImagePoint ip;
2317  ip.set_u( this->firstBorder_u );
2318  ip.set_v( this->firstBorder_v );
2319 
2320  ip_edges_list.push_back( ip );
2321 
2322  int border_u = (int)this->firstBorder_u;
2323  int border_v = (int)this->firstBorder_v;
2324 
2325  // vpTRACE("-----------------------------------------");
2326  // vpTRACE("first border_u: %d border_v: %d dir: %d",
2327  // this->firstBorder_u, this->firstBorder_v,firstDir);
2328  int du, dv;
2329  float dS, dMu, dMv, dMuv, dMu2, dMv2;
2330  m00 = 0.0;
2331  m10 = 0.0;
2332  m01 = 0.0;
2333  m11 = 0.0;
2334  m20 = 0.0;
2335  m02 = 0.0;
2336  // while we didn't come back to the first point, follow the border
2337  do {
2338  // if it was asked, show the border
2339  if (graphics) {
2340  ip.set_u ( border_u );
2341  ip.set_v ( border_v );
2342 
2344  //vpDisplay::flush(I);
2345  }
2346 #ifdef DEBUG
2347  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
2348  vpDisplay::flush(I);
2349 #endif
2350  // Determine the increments for the parameters
2351  computeFreemanParameters(border_u, border_v, dir, du, dv,
2352  dS, // surface
2353  dMu, dMv, // first order moments
2354  dMuv, dMu2, dMv2); // second order moment
2355 
2356  // Update the parameters
2357  border_u += du; // Next position on the border
2358  border_v += dv;
2359  m00 += dS; // enclosed area
2360  m10 += dMu; // First order moment along v axis
2361  m01 += dMv; // First order moment along u axis
2362  if (compute_moment) {
2363  m11 += dMuv; // Second order moment
2364  m20 += dMu2; // Second order moment along v axis
2365  m02 += dMv2; // Second order moment along u axis
2366  }
2367  // if we are now out of the image, return an error tracking
2368  if( !isInArea( (unsigned int)border_u, (unsigned int)border_v ) ) {
2369 
2370  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
2371  // Can Occur on a single pixel dot located on the top border
2372  return false;
2373  }
2374 
2375  // store the new direction and dot border coordinates.
2376 
2377  direction_list.push_back( dir );
2378 
2379  ip.set_u( border_u );
2380  ip.set_v( border_v );
2381  ip_edges_list.push_back( ip );
2382 
2383  // vpDisplay::getClick(I);
2384 
2385  // update the extreme point of the dot.
2386  if( border_v < bbox_v_min ) bbox_v_min = border_v;
2387  if( border_v > bbox_v_max ) bbox_v_max = border_v;
2388  if( border_u < bbox_u_min ) bbox_u_min = border_u;
2389  if( border_u > bbox_u_max ) bbox_u_max = border_u;
2390 
2391  // move around the tracked entity by following the border.
2392  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
2393  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)",
2394  border_u, border_v);
2395  return false;
2396  }
2397 
2398  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v, dir);
2399 
2400  }
2401  while( (getFirstBorder_u() != (unsigned int)border_u
2402  || getFirstBorder_v() != (unsigned int)border_v
2403  || firstDir != dir) &&
2404  isInArea( (unsigned int)border_u, (unsigned int)border_v ) );
2405 
2406 #ifdef VP_DEBUG
2407 #if VP_DEBUG_MODE == 3
2408  vpDisplay::flush(I);
2409 #endif
2410 #endif
2411 
2412  // if the surface is one or zero , the center of gravity wasn't properly
2413  // detected. Return an error tracking.
2414  //if( m00 == 0 || m00 == 1 )
2415  if( std::fabs(m00) <= std::numeric_limits<double>::epsilon()
2416  || std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.)*std::numeric_limits<double>::epsilon() )
2417  {
2418  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
2419  return false;
2420  }
2421  else // compute the center
2422  {
2423  // this magic formula gives the coordinates of the center of gravity
2424  double tmpCenter_u = m10 / m00;
2425  double tmpCenter_v = m01 / m00;
2426 
2427  //Updates the central moments
2428  if (compute_moment)
2429  {
2430  mu11 = m11 - tmpCenter_u*m01;
2431  mu02 = m02 - tmpCenter_v*m01;
2432  mu20 = m20 - tmpCenter_u*m10;
2433  }
2434 
2435 
2436  // check the center is in the image... never know...
2437  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
2438  // (unsigned int)tmpCenter_v ) )
2439  // {
2440  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has not a good in level", tmpCenter_u, tmpCenter_v);
2441  // return false;
2442  // }
2443 
2444  cog.set_u( tmpCenter_u );
2445  cog.set_v( tmpCenter_v );
2446  }
2447 
2448  width = bbox_u_max - bbox_u_min + 1;
2449  height = bbox_v_max - bbox_v_min + 1;
2450  surface = m00;
2451 
2452  computeMeanGrayLevel(I);
2453  return true;
2454 }
2455 
2456 
2472 bool
2473  vpDot2::findFirstBorder(const vpImage<unsigned char> &I,
2474  const unsigned int &u,
2475  const unsigned int &v,
2476  unsigned int &border_u,
2477  unsigned int &border_v)
2478 {
2479  // find the border
2480 
2481  // NOTE:
2482  // from here we use int and not double. This is because we don't have
2483  // rounding problems and it's actually more a trouble than smth else to
2484  // work with double when navigating around the dot.
2485  border_u = u;
2486  border_v = v;
2487  double epsilon =0.001;
2488 
2489 #ifdef DEBUG
2490  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
2491 #endif
2492  while( hasGoodLevel( I, border_u+1, border_v ) &&
2493  border_u < area.getRight()/*I.getWidth()*/ ) {
2494  // if the width of this dot was initialised and we already crossed the dot
2495  // on more than the max possible width, no need to continue, return an
2496  // error tracking
2497  if( getWidth() > 0 && ( border_u - u ) > getWidth()/(getMaxSizeSearchDistancePrecision()+epsilon) ) {
2498  vpDEBUG_TRACE(3, "The found dot (%d, %d, %d) has a greater width than the required one", u, v, border_u);
2499  return false;
2500  }
2501 #ifdef DEBUG
2502  vpDisplay::displayPoint(I, border_v, border_u+1, vpColor::green);
2503  vpDisplay::flush(I);
2504 #endif
2505 
2506  border_u++;
2507  }
2508  return true;
2509 }
2510 
2511 
2530 bool
2531  vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I,
2532  const unsigned int &u,
2533  const unsigned int &v,
2534  unsigned int &element)
2535 {
2536 
2537  if (hasGoodLevel( I, u, v )) {
2538  unsigned int _u = u;
2539  unsigned int _v = v;
2540  // get the point on the right of the point passed in
2541  updateFreemanPosition( _u, _v, (element + 2) %8 );
2542  if (hasGoodLevel( I, _u, _v )) {
2543  element = (element + 2) % 8; // turn right
2544  }
2545  else {
2546  unsigned int _u = u;
2547  unsigned int _v = v;
2548  updateFreemanPosition( _u, _v, (element + 1) %8 );
2549 
2550  if ( hasGoodLevel( I, _u, _v )) {
2551  element = (element + 1) % 8; // turn diag right
2552  }
2553  else {
2554  unsigned int _u = u;
2555  unsigned int _v = v;
2556  updateFreemanPosition( _u, _v, element ); // same direction
2557 
2558  if ( hasGoodLevel( I, _u, _v )) {
2559  element = element; // keep same dir
2560  }
2561  else {
2562  unsigned int _u = u;
2563  unsigned int _v = v;
2564  updateFreemanPosition( _u, _v, (element + 7) %8 ); // diag left
2565 
2566  if ( hasGoodLevel( I, _u, _v )) {
2567  element = (element + 7) %8; // turn diag left
2568  }
2569  else {
2570  unsigned int _u = u;
2571  unsigned int _v = v;
2572  updateFreemanPosition( _u, _v, (element + 6) %8 ); // left
2573 
2574  if ( hasGoodLevel( I, _u, _v )) {
2575  element = (element + 6) %8 ; // turn left
2576  }
2577  else {
2578  unsigned int _u = u;
2579  unsigned int _v = v;
2580  updateFreemanPosition( _u, _v, (element + 5) %8 ); // left
2581 
2582  if ( hasGoodLevel( I, _u, _v )) {
2583  element = (element + 5) %8 ; // turn diag down
2584  }
2585  else {
2586  unsigned int _u = u;
2587  unsigned int _v = v;
2588  updateFreemanPosition( _u, _v, (element + 4) %8 ); // left
2589 
2590  if ( hasGoodLevel( I, _u, _v )) {
2591  element = (element + 4) %8 ; // turn down
2592  }
2593  else {
2594  unsigned int _u = u;
2595  unsigned int _v = v;
2596  updateFreemanPosition( _u, _v, (element + 3) %8 ); // diag
2597 
2598  if ( hasGoodLevel( I, _u, _v )) {
2599  element = (element + 3) %8 ; // turn diag right down
2600  }
2601  else {
2602  // No neighbor with a good level
2603  //
2604  return false;
2605  }
2606  }
2607  }
2608  }
2609  }
2610  }
2611  }
2612  }
2613  }
2614 
2615  else {
2616  return false;
2617  }
2618 
2619  return true;
2620 
2621 }
2622 
2654 void
2655  vpDot2::computeFreemanParameters(const int &u_p,
2656  const int &v_p,
2657  unsigned int &element,
2658  int &du, int &dv,
2659  float &dS,
2660  float &dMu, float &dMv,
2661  float &dMuv,
2662  float &dMu2, float &dMv2)
2663 {
2664  du = 0;
2665  dv = 0;
2666  dMuv = 0;
2667  dMu2 = 0;
2668  dMv2 = 0;
2669 
2670  /*
2671  3 2 1
2672  \ | /
2673  \|/
2674  4 ------- 0
2675  /|\
2676  / | \
2677  5 6 7
2678  */
2679  switch(element) {
2680  case 0: // go right
2681  du = 1;
2682  dS = (float) v_p;
2683  dMu = 0.0;
2684  dMv = (float)(0.5 * v_p * v_p);
2685  if (compute_moment) {
2686  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
2687  dMu2 = 0;
2688  dMv2 = (float)(1.0/ 3. * v_p * v_p * v_p);
2689  }
2690  break;
2691 
2692  case 1: // go right top
2693  du = 1;
2694  dv = 1;
2695  dS = (float)(v_p + 0.5);
2696  dMu = - (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2697  dMv = (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2698  if (compute_moment) {
2699  float half_u_p = (float)(0.5*u_p);
2700  dMuv = (float)(v_p*v_p*(0.25+half_u_p) + v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2701  dMu2 = (float)(-1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1./12.0);
2702  dMv2 = (float)( 1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1./12.0);
2703  }
2704  break;
2705 
2706  case 2: // go top
2707  dv = 1;
2708  dS = 0.0;
2709  dMu = (float)(- 0.5 * u_p * u_p);
2710  dMv = 0.0;
2711  if (compute_moment) {
2712  dMuv = 0;
2713  dMu2 = (float)(-1.0/ 3. * u_p * u_p * u_p);
2714  dMv2 = 0;
2715  }
2716  break;
2717 
2718  case 3:
2719  du = -1;
2720  dv = 1;
2721  dS = (float)(- v_p - 0.5);
2722  dMu = - (float)(0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2723  dMv = - (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2724  if (compute_moment) {
2725  float half_u_p = (float)(0.5*u_p);
2726  dMuv = (float)(v_p*v_p*(0.25-half_u_p) + v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2727  dMu2 = (float)(-1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2728  dMv2 = (float)(-1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1./12.0);
2729  }
2730  break;
2731 
2732  case 4:
2733  du = -1;
2734  dS = (float)(- v_p);
2735  dMv = (float)(- 0.5 * v_p * v_p);
2736  dMu = 0.0;
2737  if (compute_moment) {
2738  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2739  dMu2 = 0;
2740  dMv2 = (float)(-1.0/ 3. * v_p * v_p * v_p);
2741  }
2742  break;
2743 
2744  case 5:
2745  du = -1;
2746  dv = -1;
2747  dS = (float)(- v_p + 0.5);
2748  dMu = (float)( 0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2749  dMv = (float)(- (0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0));
2750  if (compute_moment) {
2751  float half_u_p = (float)(0.5*u_p);
2752  dMuv = (float)(v_p*v_p*(0.25-half_u_p) - v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2753  dMu2 = (float)( 1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2754  dMv2 = (float)(-1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2755  }
2756  break;
2757 
2758  case 6:
2759  dv = -1;
2760  dS = 0.0;
2761  dMu = (float)(0.5 * u_p * u_p);
2762  dMv = 0.0;
2763  if (compute_moment) {
2764  dMuv = 0;
2765  dMu2 = (float)(1.0/ 3. * u_p * u_p * u_p);
2766  dMv2 = 0;
2767  }
2768  break;
2769 
2770  case 7:
2771  du = 1;
2772  dv = -1;
2773  dS = (float)(v_p - 0.5);
2774  dMu = (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2775  dMv = (float)(0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0);
2776  if (compute_moment) {
2777  float half_u_p = (float)(0.5*u_p);
2778  dMuv = (float)(v_p*v_p*(0.25+half_u_p) - v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2779  dMu2 = (float)(1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1./12.0);
2780  dMv2 = (float)(1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2781  }
2782  break;
2783  }
2784 }
2785 
2786 
2800 void vpDot2::updateFreemanPosition( unsigned int& u, unsigned int& v,
2801  const unsigned int &dir )
2802 {
2803  switch(dir) {
2804  case 0: u += 1; break;
2805  case 1: u += 1; v += 1; break;
2806  case 2: v += 1; break;
2807  case 3: u -= 1; v += 1; break;
2808  case 4: u -= 1; break;
2809  case 5: u -= 1; v -= 1; break;
2810  case 6: v -= 1; break;
2811  case 7: u += 1; v -= 1; break;
2812  }
2813 }
2814 
2826 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const
2827 {
2828  return isInImage( I, cog);
2829 }
2830 
2842 bool vpDot2::isInImage(const vpImage<unsigned char> &I,
2843  const vpImagePoint &ip) const
2844 {
2845  unsigned int height = I.getHeight();
2846  unsigned int width = I.getWidth();
2847  double u = ip.get_u();
2848  double v = ip.get_v();
2849 
2850  if( u < 0 || u >= width ) return false;
2851  if( v < 0 || v >= height ) return false;
2852  return true;
2853 }
2854 
2866 bool vpDot2::isInArea( const unsigned int &u, const unsigned int &v) const
2867 {
2868  unsigned int area_u_min = (unsigned int) area.getLeft();
2869  unsigned int area_u_max = (unsigned int) area.getRight();
2870  unsigned int area_v_min = (unsigned int) area.getTop();
2871  unsigned int area_v_max = (unsigned int) area.getBottom();
2872 
2873  if( u < area_u_min || u > area_u_max ) return false;
2874  if( v < area_v_min || v > area_v_max ) return false;
2875  return true;
2876 }
2877 
2878 
2890 void vpDot2::getGridSize( unsigned int &gridWidth, unsigned int &gridHeight )
2891 {
2892  // first get the research grid width and height Note that
2893  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2894  // contained in the dot. We gent this here if the dot is a perfect disc.
2895  // More accurate criterium to define the grid should be implemented if
2896  // necessary
2897  gridWidth = (unsigned int) (getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2898  gridHeight = (unsigned int) (getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2899 
2900  if( gridWidth == 0 ) gridWidth = 1;
2901  if( gridHeight == 0 ) gridHeight = 1;
2902 }
2903 
2904 
2905 
2918 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char>& I)
2919 {
2920  int cog_u = (int)cog.get_u();
2921  int cog_v = (int)cog.get_v();
2922 
2923  unsigned int sum_value =0;
2924  unsigned int nb_pixels =0;
2925 
2926  for(unsigned int i=(unsigned int)this->bbox_u_min; i <=(unsigned int)this->bbox_u_max ; i++){
2927  unsigned int pixel_gray =(unsigned int) I[(unsigned int)cog_v][i];
2928  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2929  sum_value += pixel_gray;
2930  nb_pixels ++;
2931  }
2932  }
2933  for(unsigned int i=(unsigned int)this->bbox_v_min; i <=(unsigned int)this->bbox_v_max ; i++){
2934  unsigned char pixel_gray =I[i][(unsigned int)cog_u];
2935  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2936  sum_value += pixel_gray;
2937  nb_pixels ++;
2938  }
2939  }
2940  if(nb_pixels < 10){ //could be good to choose the min nb points from area of dot
2941  //add diagonals points to have enough point
2942  int imin,imax;
2943  if( (cog_u - bbox_u_min) > (cog_v - bbox_v_min)){
2944  imin=cog_v - bbox_v_min;
2945  }
2946  else{ imin = cog_u - bbox_u_min;}
2947  if( (bbox_u_max - cog_u) > (bbox_v_max - cog_v)){
2948  imax=bbox_v_max - cog_v;
2949  }
2950  else{ imax = bbox_u_max - cog_u;}
2951  for(int i=-imin; i <=imax ; i++){
2952  unsigned int pixel_gray =(unsigned int) I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2953  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2954  sum_value += pixel_gray;
2955  nb_pixels ++;
2956  }
2957  }
2958 
2959  if( (cog_u - bbox_u_min) > (bbox_v_max - cog_v)){
2960  imin = bbox_v_max - cog_v;
2961  }
2962  else{ imin = cog_u - bbox_u_min;}
2963  if( (bbox_u_max - cog_u) > (cog_v - bbox_v_min)){
2964  imax = cog_v - bbox_v_min;
2965  }
2966  else{ imax = bbox_u_max - cog_u;}
2967 
2968  for(int i=-imin; i <=imax ; i++){
2969  unsigned char pixel_gray =I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2970  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2971  sum_value += pixel_gray;
2972  nb_pixels ++;
2973  }
2974  }
2975  }
2976 
2977  if(nb_pixels== 0){
2978  //should never happen
2980  }
2981  else{
2982  mean_gray_level = sum_value/nb_pixels;
2983  }
2984 }
2985 
2986 
3002 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I, vpColor col, bool trackDot)
3003 {
3004  vpMatrix Cogs(n, 2);
3005  vpImagePoint cog;
3006  unsigned int i;
3007  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
3008  if(fromFile)
3009  {
3010  vpMatrix::loadMatrix(dotFile, Cogs);
3011  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
3012  }
3013 
3014  // test number of cogs in file
3015  if(Cogs.getRows() < n)
3016  {
3017  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
3018  fromFile = false;
3019  }
3020 
3021  // read from file and tracks the dots
3022  if(fromFile)
3023  {
3024  try
3025  {
3026  for(i=0;i<n;++i)
3027  {
3028  cog.set_uv(Cogs[i][0], Cogs[i][1]);
3029  dot[i].setGraphics(true);
3030  dot[i].setCog(cog);
3031  if(trackDot)
3032  {
3033  dot[i].initTracking(I,cog);
3034  dot[i].track(I);
3035  vpDisplay::displayCross(I, cog, 10, col);
3036  }
3037  }
3038  }
3039  catch(...)
3040  {
3041  std::cout << "Cannot track dots from file" << std::endl;
3042  fromFile = false;
3043  }
3044  vpDisplay::flush(I);
3045 
3046  // check that dots are far away ones from the other
3047  double d;
3048  for(i=0;i<n && fromFile;++i)
3049  {
3050  d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
3051  for(unsigned int j=0;j<n && fromFile;++j)
3052  if(j!=i)
3053  if(dot[i].getDistance(dot[j]) < d)
3054  {
3055  fromFile = false;
3056  std::cout << "Dots from file seem incoherent" << std::endl;
3057  }
3058  }
3059  }
3060 
3061  if(!fromFile)
3062  {
3063  vpDisplay::display(I);
3064  vpDisplay::flush(I);
3065 
3066  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
3067  for (i = 0; i < n; i++)
3068  {
3069  if(trackDot)
3070  {
3071  dot[i].setGraphics(true);
3072  dot[i].initTracking(I);
3073  cog = dot[i].getCog();
3074  }
3075  else
3076  {
3077  vpDisplay::getClick(I, cog);
3078  dot[i].setCog(cog);
3079  }
3080  Cogs[i][0] = cog.get_u();
3081  Cogs[i][1] = cog.get_v();
3082  vpDisplay::displayCross(I, cog, 10, col);
3083  vpDisplay::flush(I);
3084  }
3085  }
3086 
3087  if (!fromFile & (dotFile != ""))
3088  {
3089  vpMatrix::saveMatrix(dotFile, Cogs);
3090  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
3091  }
3092 
3093  // back to non graphic mode
3094  for(i=0;i<n;++i)
3095  dot[i].setGraphics(false);
3096 
3097  return Cogs;
3098 }
3099 
3109 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I, std::vector<vpImagePoint> &cogs, vpImagePoint* cogStar)
3110 {
3111  unsigned int i;
3112  // tracking
3113  for(i=0;i<n;++i)
3114  {
3115  dot[i].track(I);
3116  cogs.push_back(dot[i].getCog());
3117  }
3118  // trajectories
3119  for(i=n;i<cogs.size();++i)
3120  vpDisplay::displayCircle(I,cogs[i],4,vpColor::green,true);
3121  // initial position
3122  for(i=0;i<n;++i)
3123  vpDisplay::displayCircle(I,cogs[i],4,vpColor::blue,true);
3124  // if exists, desired position
3125  if(cogStar != NULL)
3126  for(i=0;i<n;++i)
3127  {
3128  vpDisplay::displayDotLine(I,cogStar[i],dot[i].getCog(),vpColor::red);
3129  vpDisplay::displayCircle(I,cogStar[i],4,vpColor::red,true);
3130  }
3131  vpDisplay::flush(I);
3132 }
3133 
3149  const std::list<vpImagePoint> &edges_list, vpColor color,
3150  unsigned int thickness)
3151 {
3152  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
3153  std::list<vpImagePoint>::const_iterator it;
3154 
3155  for (it = edges_list.begin(); it != edges_list.end(); ++it)
3156  {
3157  vpDisplay::displayPoint(I, *it, color);
3158  }
3159 }
3160 
3161 
3162 /*
3163  * Local variables:
3164  * c-basic-offset: 2
3165  * End:
3166  */
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:622
Definition of the vpMatrix class.
Definition: vpMatrix.h:96
double m02
Definition: vpDot2.h:379
double getTop() const
Definition: vpRect.h:169
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:207
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:1584
double mu02
Definition: vpDot2.h:398
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:154
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:867
#define vpERROR_TRACE
Definition: vpDebug.h:379
void setCog(const vpImagePoint &cog)
Definition: vpDot2.h:126
#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:3409
double getSurface() const
Definition: vpDot2.cpp:642
Class to define colors available for display functionnalities.
Definition: vpColor.h:123
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:157
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:652
double get_u() const
Definition: vpImagePoint.h:239
double m11
Definition: vpDot2.h:363
double getHeight() const
Definition: vpDot2.cpp:632
void kill()
Destroy the list.
Definition: vpList.h:694
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:674
double getRight() const
Definition: vpRect.h:162
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:691
static const vpColor green
Definition: vpColor.h:168
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:114
double m01
Definition: vpDot2.h:355
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:439
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1964
double get_j() const
Definition: vpImagePoint.h:192
double getSizePrecision() const
Definition: vpDot2.cpp:662
void setSurface(const double &surface)
Definition: vpDot2.cpp:742
void next(void)
position the current element on the next one
Definition: vpList.h:275
static const vpColor red
Definition: vpColor.h:165
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:254
static bool checkFilename(const char *filename)
Definition: vpIoTools.cpp:439
double getBottom() const
Definition: vpRect.h:98
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:763
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:388
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:684
void set_u(const double u)
Definition: vpImagePoint.h:203
double m20
Definition: vpDot2.h:370
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:3482
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:2197
void operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:138
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:186
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:291
void setComputeMoments(const bool activate)
Definition: vpDot2.h:143
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 setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:838
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:196
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:191
void setWidth(const double &width)
Definition: vpDot2.cpp:712
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:3109
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:793
double getMeanGrayLevel()
Definition: vpDot2.h:311
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:240
void setHeight(const double &height)
Definition: vpDot2.cpp:727
double m10
Definition: vpDot2.h:347
unsigned int getHeight() const
Definition: vpImage.h:145
void set_uv(const double u, const double v)
Definition: vpImagePoint.h:225
double mu20
Definition: vpDot2.h:393
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:336
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:157
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:299
static const vpColor purple
Definition: vpColor.h:176
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:3002
void setGraphics(const bool activate)
Definition: vpDot2.h:178
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
virtual ~vpDot2()
Definition: vpDot2.cpp:181
static const vpColor blue
Definition: vpColor.h:171