ViSP  2.7.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  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  thickness = twinDot.thickness;
174 
175  direction_list = twinDot.direction_list;
176  ip_edges_list = twinDot.ip_edges_list;
177 }
178 
183 
184 
185 /******************************************************************************
186  *
187  * PUBLIC METHODS
188  *****************************************************************************/
189 
198  unsigned int thickness)
199 {
200  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
201  std::list<vpImagePoint>::const_iterator it;
202 
203  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it)
204  {
205  vpDisplay::displayPoint(I, *it, color);
206  }
207 }
208 
209 
241 void vpDot2::initTracking(const vpImage<unsigned char>& I, unsigned int size)
242 {
243  while ( vpDisplay::getClick(I, cog) != true) ;
244 
245  unsigned int i = (unsigned int)cog.get_i();
246  unsigned int j = (unsigned int)cog.get_j();
247 
248  double Ip = pow((double)I[i][j]/255,1/gamma);
249 
250  if(Ip - (1 - grayLevelPrecision)<0){
251  gray_level_min = 0 ;
252  }
253  else{
254  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
255  if (gray_level_min > 255)
256  gray_level_min = 255;
257  }
258  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
259  if (gray_level_max > 255)
260  gray_level_max = 255;
261 
262  setWidth(size);
263  setHeight(size);
264 
265  try {
266  track( I );
267  }
268  catch(...)
269  {
270  vpERROR_TRACE("Error caught") ;
271  throw ;
272  }
273 }
274 
303  const vpImagePoint &ip, unsigned int size)
304 {
305  cog = ip ;
306 
307  unsigned int i = (unsigned int)cog.get_i();
308  unsigned int j = (unsigned int)cog.get_j();
309 
310  double Ip = pow((double)I[i][j]/255,1/gamma);
311 
312  if(Ip - (1 - grayLevelPrecision)<0){
313  gray_level_min = 0 ;
314  }
315  else{
316  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
317  if (gray_level_min > 255)
318  gray_level_min = 255;
319  }
320  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
321  if (gray_level_max > 255)
322  gray_level_max = 255;
323 
324  setWidth(size);
325  setHeight(size);
326 
327  try {
328  track( I );
329  }
330  catch(...)
331  {
332  vpERROR_TRACE("Error caught") ;
333  throw ;
334  }
335 }
336 
377  const vpImagePoint &ip,
378  unsigned int gray_level_min,
379  unsigned int gray_level_max,
380  unsigned int size)
381 {
382  cog = ip ;
383 
384  this->gray_level_min = gray_level_min;
385  this->gray_level_max = gray_level_max;
386 
387  setWidth(size);
388  setHeight(size);
389 
390  try {
391  track( I );
392  }
393  catch(...)
394  {
395  vpERROR_TRACE("Error caught") ;
396  throw ;
397  }
398 }
399 
400 
401 
441 {
442  m00 = m11 = m02 = m20 = m10 = m01 = 0 ;
443 
444  // First, we will estimate the position of the tracked point
445 
446  // Set the search area to the entire image
447  setArea(I);
448 
449  // create a copy of the dot to search
450  // This copy can be saw as the previous dot used to check if the current one
451  // found with computeParameters() is similar to the previous one (see isValid()
452  // function).
453  // If the found dot is not similar (or valid), we use this copy to set the current
454  // found dot to the previous one (see below).
455  vpDot2 wantedDot(*this);
456 
457  // vpDEBUG_TRACE(0, "Previous dot: ");
458  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
459  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
460  bool found = false;
461  found = computeParameters(I, cog.get_u(), cog.get_v());
462 
463  if (found) {
464  // test if the found dot is valid (ie similar to the previous one)
465  found = isValid( I, wantedDot);
466  if (! found) {
467  *this = wantedDot;
468  //std::cout << "The found dot is not valid" << std::endl;
469  }
470  }
471 
472  if (! found) {
473  // vpDEBUG_TRACE(0, "Search the dot in a bigest window around the last position");
474  // vpDEBUG_TRACE(0, "Bad computed dot: ");
475  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
476  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
477 
478  // if estimation was wrong (get an error tracking), look for the dot
479  // closest from the estimation,
480  // i.e. search for dots in an area arround the this dot and get the first
481  // element in the area.
482 
483  // first get the size of the search window from the dot size
484  double searchWindowWidth, searchWindowHeight;
485  //if( getWidth() == 0 || getHeight() == 0 )
486  if( std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() || std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon() )
487  {
488  searchWindowWidth = 80.;
489  searchWindowHeight = 80.;
490  }
491  else
492  {
493  searchWindowWidth = getWidth() * 5;
494  searchWindowHeight = getHeight() * 5;
495  }
496  std::list<vpDot2> candidates;
497  searchDotsInArea( I,
498  (int)(this->cog.get_u()-searchWindowWidth /2.0),
499  (int)(this->cog.get_v()-searchWindowHeight/2.0),
500  (unsigned int)searchWindowWidth,
501  (unsigned int)searchWindowHeight,
502  candidates);
503 
504  // if the vector is empty, that mean we didn't find any candidate
505  // in the area, return an error tracking.
506  if( candidates.empty() )
507  {
508  vpERROR_TRACE("No dot was found") ;
510  "No dot was found")) ;
511  }
512 
513  // otherwise we've got our dot, update this dot's parameters
514  vpDot2 movingDot = candidates.front();
515 
516  setCog( movingDot.getCog() );
517  setSurface( movingDot.getSurface() );
518  setWidth( movingDot.getWidth() );
519  setHeight( movingDot.getHeight() );
520 
521  // Update the moments
522  m00 = movingDot.m00;
523  m01 = movingDot.m01;
524  m10 = movingDot.m10;
525  m11 = movingDot.m11;
526  m20 = movingDot.m20;
527  m02 = movingDot.m02;
528 
529  // Update the bounding box
530  bbox_u_min = movingDot.bbox_u_min;
531  bbox_u_max = movingDot.bbox_u_max;
532  bbox_v_min = movingDot.bbox_v_min;
533  bbox_v_max = movingDot.bbox_v_max;
534  }
535  // else {
536  // // test if the found dot is valid,
537  // if( ! isValid( I, wantedDot ) ) {
538  // *this = wantedDot;
539  // vpERROR_TRACE("The found dot is invalid:",
540  // "- could be a problem of size (width or height) or "
541  // " surface (number of pixels) which differ too much "
542  // " to the previous one "
543  // "- or a problem of the shape which is not ellipsoid if "
544  // " use setEllipsoidShapePrecision(double ellipsoidShapePrecision) "
545  // " which is the default case. "
546  // " To track a non ellipsoid shape use setEllipsoidShapePrecision(0)") ;
547  // throw(vpTrackingException(vpTrackingException::featureLostError,
548  // "The found dot is invalid")) ;
549  // }
550  // }
551 
552  // if this dot is partially out of the image, return an error tracking.
553  if( !isInImage( I ) )
554  {
555  vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
557  "No dot was found")) ;
558  }
559 
560  // Get dots center of gravity
561  // unsigned int u = (unsigned int) this->cog.get_u();
562  // unsigned int v = (unsigned int) this->cog.get_v();
563  // Updates the min and max gray levels for the next iteration
564  // double Ip = pow((double)I[v][u]/255,1/gamma);
565  double Ip = pow(getMeanGrayLevel()/255,1/gamma);
566  //printf("current value of gray level center : %i\n", I[v][u]);
567 
568  //getMeanGrayLevel(I);
569  if(Ip - (1 - grayLevelPrecision)<0){
570  gray_level_min = 0 ;
571  }
572  else{
573  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
574  if (gray_level_min > 255)
575  gray_level_min = 255;
576  }
577  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
578  if (gray_level_max > 255)
579  gray_level_max = 255;
580 
581  //printf("%i %i \n",gray_level_max,gray_level_min);
582  if (graphics) {
583  // display a red cross at the center of gravity's location in the image.
584 
585  vpDisplay::displayCross(I, this->cog, 3*thickness+8, vpColor::red, thickness);
586  //vpDisplay::flush(I);
587  }
588 }
589 
608 void
610 {
611  track(I);
612 
613  cog = this->cog;
614 }
615 
617 
623 double vpDot2::getWidth() const
624 {
625  return width;
626 }
627 
633 double vpDot2::getHeight() const
634 {
635  return height;
636 }
637 
643 double vpDot2::getSurface() const
644 {
645  return fabs(surface);
646 }
647 
654 {
655  return grayLevelPrecision;
656 }
657 
664 {
665  return sizePrecision;
666 }
667 
676 {
677  return ellipsoidShapePrecision;
678 }
679 
686  return maxSizeSearchDistancePrecision;
687 }
688 
692 double vpDot2::getDistance( const vpDot2& distantDot ) const
693 {
694  vpImagePoint cogDistantDot = distantDot.getCog();
695  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
696  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
697  return sqrt( diff_u*diff_u + diff_v*diff_v );
698 }
699 
700 
702 
703 
713 void vpDot2::setWidth( const double & width )
714 {
715  this->width = width;
716 }
717 
728 void vpDot2::setHeight( const double & height )
729 {
730  this->height = height;
731 }
732 
743 void vpDot2::setSurface( const double & surface )
744 {
745  this->surface = surface;
746 }
747 
764 void vpDot2::setGrayLevelPrecision( const double & grayLevelPrecision )
765 {
766  double epsilon = 0.05;
767  if( grayLevelPrecision<epsilon )
768  {
769  this->grayLevelPrecision = epsilon;
770  }
771  else if( grayLevelPrecision>1 )
772  {
773  this->grayLevelPrecision = 1.0;
774  }
775  else
776  {
777  this->grayLevelPrecision = grayLevelPrecision;
778  }
779 }
794 void vpDot2::setSizePrecision( const double & sizePrecision )
795 {
796  if( sizePrecision<0 )
797  {
798  this->sizePrecision = 0;
799  }
800  else if( sizePrecision>1 )
801  {
802  this->sizePrecision = 1.0;
803  }
804  else
805  {
806  this->sizePrecision = sizePrecision;
807  }
808 }
809 
839 void vpDot2::setEllipsoidShapePrecision(const double & ellipsoidShapePrecision) {
840 
841  if( ellipsoidShapePrecision<0 )
842  {
843  this->ellipsoidShapePrecision = 0;
844  }
845  else if( ellipsoidShapePrecision>1 )
846  {
847  this->ellipsoidShapePrecision = 1.0;
848  }
849  else
850  {
851  this->ellipsoidShapePrecision = ellipsoidShapePrecision;
852  }
853 }
854 
868 void vpDot2::setMaxSizeSearchDistancePrecision( const double & maxSizeSearchDistancePrecision )
869 {
870  double epsilon = 0.05;
871  if( maxSizeSearchDistancePrecision<epsilon )
872  {
873  this-> maxSizeSearchDistancePrecision = epsilon;
874  }
875  else if( maxSizeSearchDistancePrecision >1 )
876  {
877  this->maxSizeSearchDistancePrecision = 1.0;
878  }
879  else
880  {
881  this->maxSizeSearchDistancePrecision = maxSizeSearchDistancePrecision;
882  }
883 }
884 
893 void
894 vpDot2::setArea(const vpImage<unsigned char> &I)
895 {
896  setArea(I, 0, 0, I.getWidth(), I.getHeight());
897 }
898 
911 void
912 vpDot2::setArea(const vpImage<unsigned char> &I,
913  int u, int v,
914  unsigned int w, unsigned int h)
915 {
916  unsigned int image_w = I.getWidth();
917  unsigned int image_h = I.getHeight();
918 
919  // Bounds the area to the image
920  if (u < 0) u = 0;
921  else if (u >= (int)image_w) u = (int)image_w - 1;
922  if (v < 0) v = 0;
923  else if (v >= (int)image_h) v = (int)image_h - 1;
924 
925  if (((unsigned int)u + w) > image_w) w = image_w - (unsigned int)u - 1;
926  if (((unsigned int)v + h) > image_h) h = image_h - (unsigned int)v - 1;
927 
928  area.setRect(u, v, w, h);
929 }
930 
938 void
939  vpDot2::setArea(const vpRect & a)
940 {
941  area = a;
942 }
943 
945 
946 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
947 
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
1026  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
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->setGraphicsThickness( thickness );
1149  dotToTest->setComputeMoments( true );
1150  dotToTest->setArea( area );
1151  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1152 
1153  // first compute the parameters of the dot.
1154  // if for some reasons this caused an error tracking
1155  // (dot partially out of the image...), check the next intersection
1156  if( dotToTest->computeParameters( I ) == false ) {
1157  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1158  u = border_u;
1159  v = border_v;
1160  continue;
1161  }
1162  // if the dot to test is valid,
1163  if( dotToTest->isValid( I, *this ) )
1164  {
1165  vpImagePoint cogDotToTest = dotToTest->getCog();
1166  // Compute the distance to the center. The center used here is not the
1167  // area center available by area.getCenter(area_center_u,
1168  // area_center_v) but the center of the input area which may be
1169  // partially outside the image.
1170 
1171  double area_center_u = area_u + area_w/2.0 - 0.5;
1172  double area_center_v = area_v + area_h/2.0 - 0.5;
1173 
1174  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1175  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1176  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1177 
1178  bool stopLoop = false;
1179  niceDotsVector->front();
1180 
1181  while( !niceDotsVector->outside() && stopLoop == false )
1182  {
1183  vpDot2 tmpDot = niceDotsVector->value();
1184 
1185  //double epsilon = 0.001; // detecte +sieurs points
1186  double epsilon = 3.0;
1187  // if the center of the dot is the same than the current
1188  // don't add it, test the next point of the grid
1189  cogTmpDot = tmpDot.getCog();
1190 
1191  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1192  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1193  {
1194  stopLoop = true;
1195  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1196  u = border_u;
1197  v = border_v;
1198  continue;
1199  }
1200 
1201  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1202  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1203  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1204  otherDiff_v*otherDiff_v );
1205 
1206 
1207  // if the distance of the curent vector element to the center
1208  // is greater than the distance of this dot to the center,
1209  // then add this dot before the current vector element.
1210  if( otherDist > thisDist )
1211  {
1212  niceDotsVector->addLeft( *dotToTest );
1213  niceDotsVector->next();
1214  stopLoop = true;
1215  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1216  u = border_u;
1217  v = border_v;
1218  continue;
1219  }
1220  niceDotsVector->next();
1221  }
1222  vpTRACE(4, "End while (%d, %d)", u, v);
1223 
1224  // if we reached the end of the vector without finding the dot
1225  // or inserting it, insert it now.
1226  if( niceDotsVector->outside() && stopLoop == false )
1227  {
1228  niceDotsVector->end();
1229  niceDotsVector->addRight( *dotToTest );
1230  }
1231  }
1232  else {
1233  // Store bad dots
1234  badDotsVector->front();
1235  badDotsVector->addRight( *dotToTest );
1236  }
1237  }
1238  }
1239  if( dotToTest != NULL ) delete dotToTest;
1240 
1241  delete badDotsVector;
1242 
1243  //return niceDotsVector;
1244  }
1245 
1246 
1247  return niceDotsVector;
1248 
1249 }
1250 
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
1291  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
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->setGraphicsThickness( thickness );
1414  dotToTest->setComputeMoments( true );
1415  dotToTest->setArea( area );
1416  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1417 
1418  // first compute the parameters of the dot.
1419  // if for some reasons this caused an error tracking
1420  // (dot partially out of the image...), check the next intersection
1421  if( dotToTest->computeParameters( I ) == false ) {
1422  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1423  u = border_u;
1424  v = border_v;
1425  continue;
1426  }
1427  // if the dot to test is valid,
1428  if( dotToTest->isValid( I, *this ) )
1429  {
1430  vpImagePoint cogDotToTest = dotToTest->getCog();
1431  // Compute the distance to the center. The center used here is not the
1432  // area center available by area.getCenter(area_center_u,
1433  // area_center_v) but the center of the input area which may be
1434  // partially outside the image.
1435 
1436  double area_center_u = area_u + area_w/2.0 - 0.5;
1437  double area_center_v = area_v + area_h/2.0 - 0.5;
1438 
1439  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1440  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1441  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1442 
1443  bool stopLoop = false;
1444  niceDotsVector->front();
1445 
1446  while( !niceDotsVector->outside() && stopLoop == false )
1447  {
1448  vpDot2 tmpDot = niceDotsVector->value();
1449 
1450  //double epsilon = 0.001; // detecte +sieurs points
1451  double epsilon = 3.0;
1452  // if the center of the dot is the same than the current
1453  // don't add it, test the next point of the grid
1454  cogTmpDot = tmpDot.getCog();
1455 
1456  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1457  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1458  {
1459  stopLoop = true;
1460  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1461  u = border_u;
1462  v = border_v;
1463  continue;
1464  }
1465 
1466  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1467  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1468  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1469  otherDiff_v*otherDiff_v );
1470 
1471 
1472  // if the distance of the curent vector element to the center
1473  // is greater than the distance of this dot to the center,
1474  // then add this dot before the current vector element.
1475  if( otherDist > thisDist )
1476  {
1477  niceDotsVector->addLeft( *dotToTest );
1478  niceDotsVector->next();
1479  stopLoop = true;
1480  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1481  u = border_u;
1482  v = border_v;
1483  continue;
1484  }
1485  niceDotsVector->next();
1486  }
1487  vpTRACE(4, "End while (%d, %d)", u, v);
1488 
1489  // if we reached the end of the vector without finding the dot
1490  // or inserting it, insert it now.
1491  if( niceDotsVector->outside() && stopLoop == false )
1492  {
1493  niceDotsVector->end();
1494  niceDotsVector->addRight( *dotToTest );
1495  }
1496  }
1497  else {
1498  // Store bad dots
1499  badDotsVector->front();
1500  badDotsVector->addRight( *dotToTest );
1501  }
1502  }
1503  }
1504  if( dotToTest != NULL ) delete dotToTest;
1505 
1506  delete badDotsVector;
1507 
1508  return niceDotsVector;
1509 }
1510 #endif // VISP_BUILD_DEPRECATED_FUNCTIONS
1511 
1559 void vpDot2::searchDotsInArea(const vpImage<unsigned char>& I, std::list<vpDot2> &niceDots)
1560 {
1561  searchDotsInArea( I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
1562 }
1563 
1586  int area_u,
1587  int area_v,
1588  unsigned int area_w,
1589  unsigned int area_h,
1590  std::list<vpDot2> &niceDots)
1591 
1592 {
1593  // clear the list of nice dots
1594  niceDots.clear();
1595 
1596  // Fit the input area in the image; we keep only the common part between this
1597  // area and the image.
1598  setArea(I, area_u, area_v, area_w, area_h);
1599 
1600  // compute the size of the search grid
1601  unsigned int gridWidth;
1602  unsigned int gridHeight;
1603  getGridSize( gridWidth, gridHeight );
1604 
1605  if (graphics) {
1606  // Display the area were the dot is search
1607  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
1608  //vpDisplay::flush(I);
1609  }
1610 
1611 #ifdef DEBUG
1613  vpDisplay::flush(I);
1614 #endif
1615  // start the search loop; for all points of the search grid,
1616  // test if the pixel belongs to a valid dot.
1617  // if it is so eventually add it to the vector of valid dots.
1618  std::list<vpDot2> badDotsVector;
1619  std::list<vpDot2>::iterator itnice;
1620  std::list<vpDot2>::iterator itbad;
1621 
1622  vpDot2* dotToTest = NULL;
1623  vpDot2 tmpDot;
1624 
1625  unsigned int area_u_min = (unsigned int) area.getLeft();
1626  unsigned int area_u_max = (unsigned int) area.getRight();
1627  unsigned int area_v_min = (unsigned int) area.getTop();
1628  unsigned int area_v_max = (unsigned int) area.getBottom();
1629 
1630  unsigned int u, v;
1631  vpImagePoint cogTmpDot;
1632 
1633  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1634  {
1635  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1636  {
1637  // if the pixel we're in doesn't have the right color (outside the
1638  // graylevel interval), no need to check futher, just get to the
1639  // next grid intersection.
1640  if( !hasGoodLevel(I, u, v) ) continue;
1641 
1642  // Test if an other germ is inside the bounding box of a dot previoulsy
1643  // detected
1644  bool good_germ = true;
1645 
1646  itnice = niceDots.begin();
1647  while( itnice != niceDots.end() && good_germ == true) {
1648  tmpDot = *itnice;
1649 
1650  cogTmpDot = tmpDot.getCog();
1651  double u0 = cogTmpDot.get_u();
1652  double v0 = cogTmpDot.get_v();
1653  double half_w = tmpDot.getWidth() / 2.;
1654  double half_h = tmpDot.getHeight() / 2.;
1655 
1656  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1657  v >= (v0-half_h) && v <= (v0+half_h) ) {
1658  // Germ is in a previously detected dot
1659  good_germ = false;
1660  }
1661  ++ itnice;
1662  }
1663 
1664  if (! good_germ)
1665  continue;
1666 
1667  // Compute the right border position for this possible germ
1668  unsigned int border_u;
1669  unsigned int border_v;
1670  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1671  // germ is not good.
1672  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1673  u = border_u;
1674  v = border_v;
1675  continue;
1676  }
1677 
1678  itbad = badDotsVector.begin();
1679 #define vpBAD_DOT_VALUE (*itbad)
1680  vpImagePoint cogBadDot;
1681 
1682  while( itbad != badDotsVector.end() && good_germ == true) {
1683  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1684  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1685  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1686  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max){
1687  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1688  while (it_edges != ip_edges_list.end() && good_germ == true){
1689  // Test if the germ belong to a previously detected dot:
1690  // - from the germ go right to the border and compare this
1691  // position to the list of pixels of previously detected dots
1692  cogBadDot = *it_edges;
1693  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1694  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() )
1695  &&
1696  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() )) {
1697  good_germ = false;
1698  }
1699  ++ it_edges;
1700  }
1701  }
1702  ++itbad;
1703  }
1704 #undef vpBAD_DOT_VALUE
1705 
1706  if (! good_germ) {
1707  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1708  u = border_u;
1709  v = border_v;
1710  continue;
1711  }
1712 
1713  vpTRACE(4, "Try germ (%d, %d)", u, v);
1714 
1715  vpImagePoint germ;
1716  germ.set_u( u );
1717  germ.set_v( v );
1718 
1719  // otherwise estimate the width, height and surface of the dot we
1720  // created, and test it.
1721  if( dotToTest != NULL ) delete dotToTest;
1722  dotToTest = getInstance();
1723  dotToTest->setCog( germ );
1724  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1725  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1727  dotToTest->setSizePrecision( getSizePrecision() );
1728  dotToTest->setGraphics( graphics );
1729  dotToTest->setGraphicsThickness( thickness );
1730  dotToTest->setComputeMoments( true );
1731  dotToTest->setArea( area );
1732  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1733 
1734  // first compute the parameters of the dot.
1735  // if for some reasons this caused an error tracking
1736  // (dot partially out of the image...), check the next intersection
1737  if( dotToTest->computeParameters( I ) == false ) {
1738  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1739  u = border_u;
1740  v = border_v;
1741  continue;
1742  }
1743  // if the dot to test is valid,
1744  if( dotToTest->isValid( I, *this ) )
1745  {
1746  vpImagePoint cogDotToTest = dotToTest->getCog();
1747  // Compute the distance to the center. The center used here is not the
1748  // area center available by area.getCenter(area_center_u,
1749  // area_center_v) but the center of the input area which may be
1750  // partially outside the image.
1751 
1752  double area_center_u = area_u + area_w/2.0 - 0.5;
1753  double area_center_v = area_v + area_h/2.0 - 0.5;
1754 
1755  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1756  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1757  double thisDist = sqrt( thisDiff_u*thisDiff_u + thisDiff_v*thisDiff_v);
1758 
1759  bool stopLoop = false;
1760  itnice = niceDots.begin();
1761 
1762  while( itnice != niceDots.end() && stopLoop == false )
1763  {
1764  vpDot2 tmpDot = *itnice;
1765 
1766  //double epsilon = 0.001; // detecte +sieurs points
1767  double epsilon = 3.0;
1768  // if the center of the dot is the same than the current
1769  // don't add it, test the next point of the grid
1770  cogTmpDot = tmpDot.getCog();
1771 
1772  if( fabs( cogTmpDot.get_u() - cogDotToTest.get_u() ) < epsilon &&
1773  fabs( cogTmpDot.get_v() - cogDotToTest.get_v() ) < epsilon )
1774  {
1775  stopLoop = true;
1776  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1777  u = border_u;
1778  v = border_v;
1779  continue;
1780  }
1781 
1782  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1783  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1784  double otherDist = sqrt( otherDiff_u*otherDiff_u +
1785  otherDiff_v*otherDiff_v );
1786 
1787 
1788  // if the distance of the curent vector element to the center
1789  // is greater than the distance of this dot to the center,
1790  // then add this dot before the current vector element.
1791  if( otherDist > thisDist )
1792  {
1793  niceDots.insert(itnice, *dotToTest );
1794  ++ itnice;
1795  stopLoop = true;
1796  // Jump all the pixels between v,u and v, tmpDot->getFirstBorder_u()
1797  u = border_u;
1798  v = border_v;
1799  continue;
1800  }
1801  ++itnice;
1802  }
1803  vpTRACE(4, "End while (%d, %d)", u, v);
1804 
1805  // if we reached the end of the vector without finding the dot
1806  // or inserting it, insert it now.
1807  if( itnice == niceDots.end() && stopLoop == false )
1808  {
1809  niceDots.push_back( *dotToTest );
1810  }
1811  }
1812  else {
1813  // Store bad dots
1814  badDotsVector.push_front( *dotToTest );
1815  }
1816  }
1817  }
1818  if( dotToTest != NULL ) delete dotToTest;
1819 }
1820 
1841 bool vpDot2::isValid(const vpImage<unsigned char>& I, const vpDot2& wantedDot )
1842 {
1843  double sizePrecision = wantedDot.getSizePrecision();
1844  double ellipsoidShapePrecision = wantedDot.getEllipsoidShapePrecision();
1845  double epsilon = 0.001;
1846 
1847  //
1848  // First, check the width, height and surface of the dot. Those parameters
1849  // must be the same.
1850  //
1851  //if ( (wantedDot.getWidth() != 0)
1852  // && (wantedDot.getHeight() != 0)
1853  // && (wantedDot.getSurface() != 0) )
1854  if ( (std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon())
1855  &&
1856  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon())
1857  &&
1858  (std::fabs(wantedDot.getSurface()) > std::numeric_limits<double>::epsilon()) )
1859  // if (sizePrecision!=0){
1860  if (std::fabs(sizePrecision) > std::numeric_limits<double>::epsilon()){
1861 #ifdef DEBUG
1862  std::cout << "test size precision......................\n";
1863  std::cout << "wanted dot: " << "w=" << wantedDot.getWidth()
1864  << " h=" << wantedDot.getHeight()
1865  << " s=" << wantedDot.getSurface()
1866  << " precision=" << sizePrecision
1867  << " epsilon=" << epsilon << std::endl;
1868  std::cout << "dot found: " << "w=" << getWidth()
1869  << " h=" << getHeight()
1870  << " s=" << getSurface() << std::endl;
1871 #endif
1872  if( ( wantedDot.getWidth()*sizePrecision-epsilon < getWidth() ) == false )
1873  {
1874  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1875  cog.get_u(), cog.get_v());
1876 #ifdef DEBUG
1877  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1878 #endif
1879  return false;
1880  }
1881 
1882  if( ( getWidth() < wantedDot.getWidth()/(sizePrecision+epsilon ) )== false )
1883  {
1884  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1885  cog.get_u(), cog.get_v());
1886 #ifdef DEBUG
1887  printf("Bad width %g > %g for dot (%g, %g)\n",
1888  getWidth(), wantedDot.getWidth()/(sizePrecision+epsilon),
1889  cog.get_u(), cog.get_v());
1890 #endif
1891  return false;
1892  }
1893 
1894  if( ( wantedDot.getHeight()*sizePrecision-epsilon < getHeight() ) == false )
1895  {
1896  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1897  cog.get_u(), cog.get_v());
1898 #ifdef DEBUG
1899  printf("Bad height %g > %g for dot (%g, %g)\n",
1900  wantedDot.getHeight()*sizePrecision-epsilon, getHeight(),
1901  cog.get_u(), cog.get_v());
1902 #endif
1903  return false;
1904  }
1905 
1906  if( ( getHeight() < wantedDot.getHeight()/(sizePrecision+epsilon )) == false )
1907  {
1908  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1909  cog.get_u(), cog.get_v());
1910 #ifdef DEBUG
1911  printf("Bad height %g > %g for dot (%g, %g)\n",
1912  getHeight(), wantedDot.getHeight()/(sizePrecision+epsilon),
1913  cog.get_u(), cog.get_v());
1914 #endif
1915  return false;
1916  }
1917 
1918  if( ( wantedDot.getSurface()*(sizePrecision*sizePrecision)-epsilon < getSurface() ) == false )
1919  {
1920  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1921  cog.get_u(), cog.get_v());
1922 #ifdef DEBUG
1923  printf("Bad surface %g > %g for dot (%g, %g)\n",
1924  wantedDot.getSurface()*(sizePrecision*sizePrecision)-epsilon,
1925  getSurface(),
1926  cog.get_u(), cog.get_v());
1927 #endif
1928  return false;
1929  }
1930 
1931  if( ( getSurface() < wantedDot.getSurface()/(sizePrecision*sizePrecision+epsilon )) == false )
1932  {
1933  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1934  cog.get_u(), cog.get_v());
1935 #ifdef DEBUG
1936  printf("Bad surface %g < %g for dot (%g, %g)\n",
1937  getSurface(), wantedDot.getSurface()/(sizePrecision*sizePrecision+epsilon),
1938  cog.get_u(), cog.get_v());
1939 #endif
1940  return false;
1941  }
1942  }
1943  //
1944  // Now we can proceed to more advanced (and costy) checks.
1945  // First check there is a white (>level) elipse within dot
1946  // Then check the dot is surrounded by a black elipse.
1947  //
1948  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1949  int nb_bad_points = 0;
1950  int nb_max_bad_points = (int)(nb_point_to_test*allowedBadPointsPercentage_);
1951  double step_angle = 2*M_PI / nb_point_to_test;
1952 
1953  // if (ellipsoidShapePrecision != 0 && compute_moment) {
1954  if (std::fabs(ellipsoidShapePrecision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1955  // std::cout << "test shape precision......................\n";
1956  // See F. Chaumette. Image moments: a general and useful set of features
1957  // for visual servoing. IEEE Trans. on Robotics, 20(4):713-723, Ao�t 2004.
1958 
1959  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1960  // = m11 - m10 * m01 / m00
1961  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1962  // = m20 - m10^2 / m00
1963  // mu02 = m02 - m01^2 / m00
1964  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1965  //
1966  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1967  //
1968  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1969 
1970  //we compute parameters of the estimated ellipse
1971  double tmp1 = (m01*m01 -m10*m10)/m00+(m20-m02);
1972  double tmp2 = m11 -m10*m01/m00 ;
1973  double Sqrt = sqrt(tmp1*tmp1 + 4*tmp2*tmp2);
1974  double a1 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 + Sqrt));
1975  double a2 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 - Sqrt));
1976  double alpha = 0.5*atan2(2*(m11*m00-m10*m01),
1977  ((m20-m02)*m00-m10*m10+m01*m01));
1978 
1979  // to be able to track small dots, minorize the ellipsoid radius for the
1980  // inner test
1981  a1 -= 1.0;
1982  a2 -= 1.0;
1983 
1984  double innerCoef = ellipsoidShapePrecision ;
1985  unsigned int u, v;
1986  double cog_u = this->cog.get_u();
1987  double cog_v = this->cog.get_v();
1988 
1989  vpImagePoint ip;
1990  nb_bad_points = 0;
1991  for( double theta = 0. ; theta<2*M_PI ; theta+= step_angle ) {
1992  u = (unsigned int) (cog_u + innerCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
1993  v = (unsigned int) (cog_v + innerCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
1994  if( ! this->hasGoodLevel( I, u, v) ) {
1995  // vpTRACE("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g)",
1996  // u, v, cog_u, cog_v);
1997 #ifdef DEBUG
1998  printf("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
1999  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
2000 #endif
2001  //return false;
2002  nb_bad_points ++;
2003  }
2004  if (graphics) {
2005  for (unsigned int t=0; t< thickness; t++) {
2006  ip.set_u( u + t );
2007  ip.set_v( v );
2009  }
2010  }
2011 #ifdef DEBUG
2013  vpDisplay::flush(I);
2014 #endif
2015  }
2016  if (nb_bad_points > nb_max_bad_points)
2017  {
2018 #ifdef DEBUG
2019  printf("Inner ellipse has %d bad points. Max allowed is %d\n",
2020  nb_bad_points, nb_max_bad_points);
2021 #endif
2022  return false;
2023  }
2024  // to be able to track small dots, maximize the ellipsoid radius for the
2025  // inner test
2026  a1 += 2.0;
2027  a2 += 2.0;
2028 
2029  double outCoef = 2-ellipsoidShapePrecision; //1.6;
2030  nb_bad_points = 0;
2031  for( double theta=0. ; theta<2*M_PI ; theta+= step_angle ) {
2032  u = (unsigned int) (cog_u + outCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
2033  v = (unsigned int) (cog_v + outCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
2034 #ifdef DEBUG
2035  //vpDisplay::displayRectangle(I, area, vpColor::yellow);
2036  vpDisplay::displayCross( I, v, u, 7, vpColor::purple ) ;
2037  vpDisplay::flush(I);
2038 #endif
2039  // If outside the area, continue
2040  if ((double)u < area.getLeft() || (double)u > area.getRight()
2041  || (double)v < area.getTop() || (double)v > area.getBottom()) {
2042  continue;
2043  }
2044  if( ! this->hasReverseLevel( I, u, v ) ) {
2045  // vpTRACE("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g)",
2046  // u, v, cog_u, cog_v);
2047 #ifdef DEBUG
2048  printf("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
2049  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
2050 #endif
2051  nb_bad_points ++;
2052  //return false;
2053  }
2054  if (graphics) {
2055  for(unsigned int t=0; t<thickness; t++) {
2056  ip.set_u( u + t);
2057  ip.set_v( v );
2058 
2060  }
2061  }
2062  }
2063  }
2064  if (nb_bad_points > nb_max_bad_points)
2065  {
2066 #ifdef DEBUG
2067  printf("Outside ellipse has %d bad points. Max allowed is %d\n",
2068  nb_bad_points, nb_max_bad_points);
2069 #endif
2070  return false;
2071  }
2072 
2073  return true;
2074 }
2075 
2076 
2077 
2095 bool vpDot2::hasGoodLevel(const vpImage<unsigned char>& I,
2096  const unsigned int &u,
2097  const unsigned int &v) const
2098 {
2099  if( !isInArea( u, v ) )
2100  return false;
2101 
2102  if( I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
2103  {
2104  return true;
2105  }
2106  else
2107  {
2108  return false;
2109  }
2110 }
2111 
2112 
2125 bool vpDot2::hasReverseLevel(const vpImage<unsigned char>& I,
2126  const unsigned int &u,
2127  const unsigned int &v) const
2128 {
2129 
2130  if( !isInArea( u, v ) )
2131  return false;
2132 
2133  if( I[v][u] < gray_level_min || I[v][u] > gray_level_max)
2134  {
2135  return true;
2136  }
2137  else
2138  {
2139  return false;
2140  }
2141 }
2142 
2143 
2152 vpDot2* vpDot2::getInstance()
2153 {
2154  return new vpDot2();
2155 }
2156 
2157 
2158 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS
2159 
2177 {
2178  std::list<unsigned int>::const_iterator it;
2179  freeman_chain.kill();
2180  for (it = direction_list.begin(); it != direction_list.end(); ++it) {
2181  freeman_chain += *it;
2182  }
2183 }
2184 #endif
2185 
2201 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain)
2202 {
2203  freeman_chain = direction_list;
2204 }
2205 
2206 
2207 
2208 /******************************************************************************
2209  *
2210  * PRIVATE METHODS
2211  *
2212  ******************************************************************************/
2213 
2214 
2215 
2247 bool vpDot2::computeParameters(const vpImage<unsigned char> &I,
2248  const double &_u,
2249  const double &_v)
2250 {
2251  direction_list.clear();
2252  ip_edges_list.clear();
2253 
2254  double est_u = _u; // estimated
2255  double est_v = _v;
2256 
2257  // if u has default value, set it to the actual center value
2258  //if( est_u == -1.0 )
2259  if( std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u),1.)*std::numeric_limits<double>::epsilon() )
2260  {
2261  est_u = this->cog.get_u();
2262  }
2263 
2264  // if v has default value, set it to the actual center value
2265  //if( est_v == -1.0 )
2266  if( std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v),1.)*std::numeric_limits<double>::epsilon() )
2267  {
2268  est_v = this->cog.get_v();
2269  }
2270 
2271  // if the estimated position of the dot is out of the image, not need to continue,
2272  // return an error tracking
2273  if( !isInArea( (unsigned int) est_u, (unsigned int) est_v ) )
2274  {
2275  vpDEBUG_TRACE(3, "Initial pixel coordinates (%d, %d) for dot tracking are not in the area",
2276  (int) est_u, (int) est_v) ;
2277  return false;
2278  }
2279 
2280  bbox_u_min = (int)I.getWidth();
2281  bbox_u_max = 0;
2282  bbox_v_min = (int)I.getHeight();
2283  bbox_v_max = 0;
2284 
2285  // if the first point doesn't have the right level then there's no point to
2286  // continue.
2287  if( !hasGoodLevel( I, (unsigned int) est_u, (unsigned int) est_v ) )
2288  {
2289  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates",
2290  (int) est_u, (int) est_v) ;
2291  return false;
2292  }
2293 
2294  // find the border
2295 
2296  if(!findFirstBorder(I, (unsigned int) est_u, (unsigned int) est_v,
2297  this->firstBorder_u, this->firstBorder_v)) {
2298 
2299  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates",
2300  (int) est_u, (int) est_v) ;
2301  return false;
2302  }
2303 
2304  unsigned int dir = 6;
2305 
2306  // Determine the first element of the Freeman chain
2307  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
2308  unsigned int firstDir = dir;
2309 
2310  // if we are now out of the image, return an error tracking
2311  if( !isInArea( this->firstBorder_u, this->firstBorder_v ) )
2312  {
2313  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area",
2314  this->firstBorder_u, this->firstBorder_v);
2315  return false;
2316  }
2317 
2318  // store the new direction and dot border coordinates.
2319  direction_list.push_back( dir );
2320  vpImagePoint ip;
2321  ip.set_u( this->firstBorder_u );
2322  ip.set_v( this->firstBorder_v );
2323 
2324  ip_edges_list.push_back( ip );
2325 
2326  int border_u = (int)this->firstBorder_u;
2327  int border_v = (int)this->firstBorder_v;
2328 
2329  // vpTRACE("-----------------------------------------");
2330  // vpTRACE("first border_u: %d border_v: %d dir: %d",
2331  // this->firstBorder_u, this->firstBorder_v,firstDir);
2332  int du, dv;
2333  float dS, dMu, dMv, dMuv, dMu2, dMv2;
2334  m00 = 0.0;
2335  m10 = 0.0;
2336  m01 = 0.0;
2337  m11 = 0.0;
2338  m20 = 0.0;
2339  m02 = 0.0;
2340  // while we didn't come back to the first point, follow the border
2341  do {
2342  // if it was asked, show the border
2343  if (graphics) {
2344  for(int t=0; t< (int)thickness; t++) {
2345  ip.set_u ( border_u + t);
2346  ip.set_v ( border_v );
2347 
2349  }
2350  //vpDisplay::flush(I);
2351  }
2352 #ifdef DEBUG
2353  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
2354  vpDisplay::flush(I);
2355 #endif
2356  // Determine the increments for the parameters
2357  computeFreemanParameters(border_u, border_v, dir, du, dv,
2358  dS, // surface
2359  dMu, dMv, // first order moments
2360  dMuv, dMu2, dMv2); // second order moment
2361 
2362  // Update the parameters
2363  border_u += du; // Next position on the border
2364  border_v += dv;
2365  m00 += dS; // enclosed area
2366  m10 += dMu; // First order moment along v axis
2367  m01 += dMv; // First order moment along u axis
2368  if (compute_moment) {
2369  m11 += dMuv; // Second order moment
2370  m20 += dMu2; // Second order moment along v axis
2371  m02 += dMv2; // Second order moment along u axis
2372  }
2373  // if we are now out of the image, return an error tracking
2374  if( !isInArea( (unsigned int)border_u, (unsigned int)border_v ) ) {
2375 
2376  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
2377  // Can Occur on a single pixel dot located on the top border
2378  return false;
2379  }
2380 
2381  // store the new direction and dot border coordinates.
2382 
2383  direction_list.push_back( dir );
2384 
2385  ip.set_u( border_u );
2386  ip.set_v( border_v );
2387  ip_edges_list.push_back( ip );
2388 
2389  // vpDisplay::getClick(I);
2390 
2391  // update the extreme point of the dot.
2392  if( border_v < bbox_v_min ) bbox_v_min = border_v;
2393  if( border_v > bbox_v_max ) bbox_v_max = border_v;
2394  if( border_u < bbox_u_min ) bbox_u_min = border_u;
2395  if( border_u > bbox_u_max ) bbox_u_max = border_u;
2396 
2397  // move around the tracked entity by following the border.
2398  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
2399  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)",
2400  border_u, border_v);
2401  return false;
2402  }
2403 
2404  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v, dir);
2405 
2406  }
2407  while( (getFirstBorder_u() != (unsigned int)border_u
2408  || getFirstBorder_v() != (unsigned int)border_v
2409  || firstDir != dir) &&
2410  isInArea( (unsigned int)border_u, (unsigned int)border_v ) );
2411 
2412 #ifdef VP_DEBUG
2413 #if VP_DEBUG_MODE == 3
2414  vpDisplay::flush(I);
2415 #endif
2416 #endif
2417 
2418  // if the surface is one or zero , the center of gravity wasn't properly
2419  // detected. Return an error tracking.
2420  //if( m00 == 0 || m00 == 1 )
2421  if( std::fabs(m00) <= std::numeric_limits<double>::epsilon()
2422  || std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.)*std::numeric_limits<double>::epsilon() )
2423  {
2424  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
2425  return false;
2426  }
2427  else // compute the center
2428  {
2429  // this magic formula gives the coordinates of the center of gravity
2430  double tmpCenter_u = m10 / m00;
2431  double tmpCenter_v = m01 / m00;
2432 
2433  //Updates the central moments
2434  if (compute_moment)
2435  {
2436  mu11 = m11 - tmpCenter_u*m01;
2437  mu02 = m02 - tmpCenter_v*m01;
2438  mu20 = m20 - tmpCenter_u*m10;
2439  }
2440 
2441 
2442  // check the center is in the image... never know...
2443  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
2444  // (unsigned int)tmpCenter_v ) )
2445  // {
2446  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has not a good in level", tmpCenter_u, tmpCenter_v);
2447  // return false;
2448  // }
2449 
2450  cog.set_u( tmpCenter_u );
2451  cog.set_v( tmpCenter_v );
2452  }
2453 
2454  width = bbox_u_max - bbox_u_min + 1;
2455  height = bbox_v_max - bbox_v_min + 1;
2456  surface = m00;
2457 
2458  computeMeanGrayLevel(I);
2459  return true;
2460 }
2461 
2462 
2478 bool
2479  vpDot2::findFirstBorder(const vpImage<unsigned char> &I,
2480  const unsigned int &u,
2481  const unsigned int &v,
2482  unsigned int &border_u,
2483  unsigned int &border_v)
2484 {
2485  // find the border
2486 
2487  // NOTE:
2488  // from here we use int and not double. This is because we don't have
2489  // rounding problems and it's actually more a trouble than smth else to
2490  // work with double when navigating around the dot.
2491  border_u = u;
2492  border_v = v;
2493  double epsilon =0.001;
2494 
2495 #ifdef DEBUG
2496  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
2497 #endif
2498  while( hasGoodLevel( I, border_u+1, border_v ) &&
2499  border_u < area.getRight()/*I.getWidth()*/ ) {
2500  // if the width of this dot was initialised and we already crossed the dot
2501  // on more than the max possible width, no need to continue, return an
2502  // error tracking
2503  if( getWidth() > 0 && ( border_u - u ) > getWidth()/(getMaxSizeSearchDistancePrecision()+epsilon) ) {
2504  vpDEBUG_TRACE(3, "The found dot (%d, %d, %d) has a greater width than the required one", u, v, border_u);
2505  return false;
2506  }
2507 #ifdef DEBUG
2508  vpDisplay::displayPoint(I, border_v, border_u+1, vpColor::green);
2509  vpDisplay::flush(I);
2510 #endif
2511 
2512  border_u++;
2513  }
2514  return true;
2515 }
2516 
2517 
2536 bool
2537  vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I,
2538  const unsigned int &u,
2539  const unsigned int &v,
2540  unsigned int &element)
2541 {
2542 
2543  if (hasGoodLevel( I, u, v )) {
2544  unsigned int _u = u;
2545  unsigned int _v = v;
2546  // get the point on the right of the point passed in
2547  updateFreemanPosition( _u, _v, (element + 2) %8 );
2548  if (hasGoodLevel( I, _u, _v )) {
2549  element = (element + 2) % 8; // turn right
2550  }
2551  else {
2552  unsigned int _u = u;
2553  unsigned int _v = v;
2554  updateFreemanPosition( _u, _v, (element + 1) %8 );
2555 
2556  if ( hasGoodLevel( I, _u, _v )) {
2557  element = (element + 1) % 8; // turn diag right
2558  }
2559  else {
2560  unsigned int _u = u;
2561  unsigned int _v = v;
2562  updateFreemanPosition( _u, _v, element ); // same direction
2563 
2564  if ( hasGoodLevel( I, _u, _v )) {
2565  //element = element; // keep same dir
2566  }
2567  else {
2568  unsigned int _u = u;
2569  unsigned int _v = v;
2570  updateFreemanPosition( _u, _v, (element + 7) %8 ); // diag left
2571 
2572  if ( hasGoodLevel( I, _u, _v )) {
2573  element = (element + 7) %8; // turn diag left
2574  }
2575  else {
2576  unsigned int _u = u;
2577  unsigned int _v = v;
2578  updateFreemanPosition( _u, _v, (element + 6) %8 ); // left
2579 
2580  if ( hasGoodLevel( I, _u, _v )) {
2581  element = (element + 6) %8 ; // turn left
2582  }
2583  else {
2584  unsigned int _u = u;
2585  unsigned int _v = v;
2586  updateFreemanPosition( _u, _v, (element + 5) %8 ); // left
2587 
2588  if ( hasGoodLevel( I, _u, _v )) {
2589  element = (element + 5) %8 ; // turn diag down
2590  }
2591  else {
2592  unsigned int _u = u;
2593  unsigned int _v = v;
2594  updateFreemanPosition( _u, _v, (element + 4) %8 ); // left
2595 
2596  if ( hasGoodLevel( I, _u, _v )) {
2597  element = (element + 4) %8 ; // turn down
2598  }
2599  else {
2600  unsigned int _u = u;
2601  unsigned int _v = v;
2602  updateFreemanPosition( _u, _v, (element + 3) %8 ); // diag
2603 
2604  if ( hasGoodLevel( I, _u, _v )) {
2605  element = (element + 3) %8 ; // turn diag right down
2606  }
2607  else {
2608  // No neighbor with a good level
2609  //
2610  return false;
2611  }
2612  }
2613  }
2614  }
2615  }
2616  }
2617  }
2618  }
2619  }
2620 
2621  else {
2622  return false;
2623  }
2624 
2625  return true;
2626 
2627 }
2628 
2660 void
2661  vpDot2::computeFreemanParameters(const int &u_p,
2662  const int &v_p,
2663  unsigned int &element,
2664  int &du, int &dv,
2665  float &dS,
2666  float &dMu, float &dMv,
2667  float &dMuv,
2668  float &dMu2, float &dMv2)
2669 {
2670  du = 0;
2671  dv = 0;
2672  dMuv = 0;
2673  dMu2 = 0;
2674  dMv2 = 0;
2675 
2676  /*
2677  3 2 1
2678  \ | /
2679  \|/
2680  4 ------- 0
2681  /|\
2682  / | \
2683  5 6 7
2684  */
2685  switch(element) {
2686  case 0: // go right
2687  du = 1;
2688  dS = (float) v_p;
2689  dMu = 0.0;
2690  dMv = (float)(0.5 * v_p * v_p);
2691  if (compute_moment) {
2692  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
2693  dMu2 = 0;
2694  dMv2 = (float)(1.0/ 3. * v_p * v_p * v_p);
2695  }
2696  break;
2697 
2698  case 1: // go right top
2699  du = 1;
2700  dv = 1;
2701  dS = (float)(v_p + 0.5);
2702  dMu = - (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2703  dMv = (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2704  if (compute_moment) {
2705  float half_u_p = (float)(0.5*u_p);
2706  dMuv = (float)(v_p*v_p*(0.25+half_u_p) + v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2707  dMu2 = (float)(-1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1./12.0);
2708  dMv2 = (float)( 1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1./12.0);
2709  }
2710  break;
2711 
2712  case 2: // go top
2713  dv = 1;
2714  dS = 0.0;
2715  dMu = (float)(- 0.5 * u_p * u_p);
2716  dMv = 0.0;
2717  if (compute_moment) {
2718  dMuv = 0;
2719  dMu2 = (float)(-1.0/ 3. * u_p * u_p * u_p);
2720  dMv2 = 0;
2721  }
2722  break;
2723 
2724  case 3:
2725  du = -1;
2726  dv = 1;
2727  dS = (float)(- v_p - 0.5);
2728  dMu = - (float)(0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2729  dMv = - (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2730  if (compute_moment) {
2731  float half_u_p = (float)(0.5*u_p);
2732  dMuv = (float)(v_p*v_p*(0.25-half_u_p) + v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2733  dMu2 = (float)(-1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2734  dMv2 = (float)(-1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1./12.0);
2735  }
2736  break;
2737 
2738  case 4:
2739  du = -1;
2740  dS = (float)(- v_p);
2741  dMv = (float)(- 0.5 * v_p * v_p);
2742  dMu = 0.0;
2743  if (compute_moment) {
2744  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2745  dMu2 = 0;
2746  dMv2 = (float)(-1.0/ 3. * v_p * v_p * v_p);
2747  }
2748  break;
2749 
2750  case 5:
2751  du = -1;
2752  dv = -1;
2753  dS = (float)(- v_p + 0.5);
2754  dMu = (float)( 0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2755  dMv = (float)(- (0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0));
2756  if (compute_moment) {
2757  float half_u_p = (float)(0.5*u_p);
2758  dMuv = (float)(v_p*v_p*(0.25-half_u_p) - v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2759  dMu2 = (float)( 1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2760  dMv2 = (float)(-1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2761  }
2762  break;
2763 
2764  case 6:
2765  dv = -1;
2766  dS = 0.0;
2767  dMu = (float)(0.5 * u_p * u_p);
2768  dMv = 0.0;
2769  if (compute_moment) {
2770  dMuv = 0;
2771  dMu2 = (float)(1.0/ 3. * u_p * u_p * u_p);
2772  dMv2 = 0;
2773  }
2774  break;
2775 
2776  case 7:
2777  du = 1;
2778  dv = -1;
2779  dS = (float)(v_p - 0.5);
2780  dMu = (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2781  dMv = (float)(0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0);
2782  if (compute_moment) {
2783  float half_u_p = (float)(0.5*u_p);
2784  dMuv = (float)(v_p*v_p*(0.25+half_u_p) - v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2785  dMu2 = (float)(1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1./12.0);
2786  dMv2 = (float)(1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2787  }
2788  break;
2789  }
2790 }
2791 
2792 
2806 void vpDot2::updateFreemanPosition( unsigned int& u, unsigned int& v,
2807  const unsigned int &dir )
2808 {
2809  switch(dir) {
2810  case 0: u += 1; break;
2811  case 1: u += 1; v += 1; break;
2812  case 2: v += 1; break;
2813  case 3: u -= 1; v += 1; break;
2814  case 4: u -= 1; break;
2815  case 5: u -= 1; v -= 1; break;
2816  case 6: v -= 1; break;
2817  case 7: u += 1; v -= 1; break;
2818  }
2819 }
2820 
2832 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const
2833 {
2834  return isInImage( I, cog);
2835 }
2836 
2848 bool vpDot2::isInImage(const vpImage<unsigned char> &I,
2849  const vpImagePoint &ip) const
2850 {
2851  unsigned int height = I.getHeight();
2852  unsigned int width = I.getWidth();
2853  double u = ip.get_u();
2854  double v = ip.get_v();
2855 
2856  if( u < 0 || u >= width ) return false;
2857  if( v < 0 || v >= height ) return false;
2858  return true;
2859 }
2860 
2872 bool vpDot2::isInArea( const unsigned int &u, const unsigned int &v) const
2873 {
2874  unsigned int area_u_min = (unsigned int) area.getLeft();
2875  unsigned int area_u_max = (unsigned int) area.getRight();
2876  unsigned int area_v_min = (unsigned int) area.getTop();
2877  unsigned int area_v_max = (unsigned int) area.getBottom();
2878 
2879  if( u < area_u_min || u > area_u_max ) return false;
2880  if( v < area_v_min || v > area_v_max ) return false;
2881  return true;
2882 }
2883 
2884 
2896 void vpDot2::getGridSize( unsigned int &gridWidth, unsigned int &gridHeight )
2897 {
2898  // first get the research grid width and height Note that
2899  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2900  // contained in the dot. We gent this here if the dot is a perfect disc.
2901  // More accurate criterium to define the grid should be implemented if
2902  // necessary
2903  gridWidth = (unsigned int) (getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2904  gridHeight = (unsigned int) (getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2905 
2906  if( gridWidth == 0 ) gridWidth = 1;
2907  if( gridHeight == 0 ) gridHeight = 1;
2908 }
2909 
2910 
2911 
2924 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char>& I)
2925 {
2926  int cog_u = (int)cog.get_u();
2927  int cog_v = (int)cog.get_v();
2928 
2929  unsigned int sum_value =0;
2930  unsigned int nb_pixels =0;
2931 
2932  for(unsigned int i=(unsigned int)this->bbox_u_min; i <=(unsigned int)this->bbox_u_max ; i++){
2933  unsigned int pixel_gray =(unsigned int) I[(unsigned int)cog_v][i];
2934  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2935  sum_value += pixel_gray;
2936  nb_pixels ++;
2937  }
2938  }
2939  for(unsigned int i=(unsigned int)this->bbox_v_min; i <=(unsigned int)this->bbox_v_max ; i++){
2940  unsigned char pixel_gray =I[i][(unsigned int)cog_u];
2941  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2942  sum_value += pixel_gray;
2943  nb_pixels ++;
2944  }
2945  }
2946  if(nb_pixels < 10){ //could be good to choose the min nb points from area of dot
2947  //add diagonals points to have enough point
2948  int imin,imax;
2949  if( (cog_u - bbox_u_min) > (cog_v - bbox_v_min)){
2950  imin=cog_v - bbox_v_min;
2951  }
2952  else{ imin = cog_u - bbox_u_min;}
2953  if( (bbox_u_max - cog_u) > (bbox_v_max - cog_v)){
2954  imax=bbox_v_max - cog_v;
2955  }
2956  else{ imax = bbox_u_max - cog_u;}
2957  for(int i=-imin; i <=imax ; i++){
2958  unsigned int pixel_gray =(unsigned int) I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2959  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2960  sum_value += pixel_gray;
2961  nb_pixels ++;
2962  }
2963  }
2964 
2965  if( (cog_u - bbox_u_min) > (bbox_v_max - cog_v)){
2966  imin = bbox_v_max - cog_v;
2967  }
2968  else{ imin = cog_u - bbox_u_min;}
2969  if( (bbox_u_max - cog_u) > (cog_v - bbox_v_min)){
2970  imax = cog_v - bbox_v_min;
2971  }
2972  else{ imax = bbox_u_max - cog_u;}
2973 
2974  for(int i=-imin; i <=imax ; i++){
2975  unsigned char pixel_gray =I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2976  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2977  sum_value += pixel_gray;
2978  nb_pixels ++;
2979  }
2980  }
2981  }
2982 
2983  if(nb_pixels== 0){
2984  //should never happen
2986  }
2987  else{
2988  mean_gray_level = sum_value/nb_pixels;
2989  }
2990 }
2991 
2992 
3008 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I, vpColor col, bool trackDot)
3009 {
3010  vpMatrix Cogs(n, 2);
3011  vpImagePoint cog;
3012  unsigned int i;
3013  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
3014  if(fromFile)
3015  {
3016  vpMatrix::loadMatrix(dotFile, Cogs);
3017  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
3018  }
3019 
3020  // test number of cogs in file
3021  if(Cogs.getRows() < n)
3022  {
3023  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
3024  fromFile = false;
3025  }
3026 
3027  // read from file and tracks the dots
3028  if(fromFile)
3029  {
3030  try
3031  {
3032  for(i=0;i<n;++i)
3033  {
3034  cog.set_uv(Cogs[i][0], Cogs[i][1]);
3035  dot[i].setGraphics(true);
3036  dot[i].setCog(cog);
3037  if(trackDot)
3038  {
3039  dot[i].initTracking(I,cog);
3040  dot[i].track(I);
3041  vpDisplay::displayCross(I, cog, 10, col);
3042  }
3043  }
3044  }
3045  catch(...)
3046  {
3047  std::cout << "Cannot track dots from file" << std::endl;
3048  fromFile = false;
3049  }
3050  vpDisplay::flush(I);
3051 
3052  // check that dots are far away ones from the other
3053  double d;
3054  for(i=0;i<n && fromFile;++i)
3055  {
3056  d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
3057  for(unsigned int j=0;j<n && fromFile;++j)
3058  if(j!=i)
3059  if(dot[i].getDistance(dot[j]) < d)
3060  {
3061  fromFile = false;
3062  std::cout << "Dots from file seem incoherent" << std::endl;
3063  }
3064  }
3065  }
3066 
3067  if(!fromFile)
3068  {
3069  vpDisplay::display(I);
3070  vpDisplay::flush(I);
3071 
3072  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
3073  for (i = 0; i < n; i++)
3074  {
3075  if(trackDot)
3076  {
3077  dot[i].setGraphics(true);
3078  dot[i].initTracking(I);
3079  cog = dot[i].getCog();
3080  }
3081  else
3082  {
3083  vpDisplay::getClick(I, cog);
3084  dot[i].setCog(cog);
3085  }
3086  Cogs[i][0] = cog.get_u();
3087  Cogs[i][1] = cog.get_v();
3088  vpDisplay::displayCross(I, cog, 10, col);
3089  vpDisplay::flush(I);
3090  }
3091  }
3092 
3093  if (!fromFile & (dotFile != ""))
3094  {
3095  vpMatrix::saveMatrix(dotFile, Cogs);
3096  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
3097  }
3098 
3099  // back to non graphic mode
3100  for(i=0;i<n;++i)
3101  dot[i].setGraphics(false);
3102 
3103  return Cogs;
3104 }
3105 
3115 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I, std::vector<vpImagePoint> &cogs, vpImagePoint* cogStar)
3116 {
3117  unsigned int i;
3118  // tracking
3119  for(i=0;i<n;++i)
3120  {
3121  dot[i].track(I);
3122  cogs.push_back(dot[i].getCog());
3123  }
3124  // trajectories
3125  for(i=n;i<cogs.size();++i)
3126  vpDisplay::displayCircle(I,cogs[i],4,vpColor::green,true);
3127  // initial position
3128  for(i=0;i<n;++i)
3129  vpDisplay::displayCircle(I,cogs[i],4,vpColor::blue,true);
3130  // if exists, desired position
3131  if(cogStar != NULL)
3132  for(i=0;i<n;++i)
3133  {
3134  vpDisplay::displayDotLine(I,cogStar[i],dot[i].getCog(),vpColor::red);
3135  vpDisplay::displayCircle(I,cogStar[i],4,vpColor::red,true);
3136  }
3137  vpDisplay::flush(I);
3138 }
3139 
3155  const std::list<vpImagePoint> &edges_list, vpColor color,
3156  unsigned int thickness)
3157 {
3158  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
3159  std::list<vpImagePoint>::const_iterator it;
3160 
3161  for (it = edges_list.begin(); it != edges_list.end(); ++it)
3162  {
3163  vpDisplay::displayPoint(I, *it, color);
3164  }
3165 }
3166 
3182  const std::list<vpImagePoint> &edges_list, vpColor color,
3183  unsigned int thickness)
3184 {
3185  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
3186  std::list<vpImagePoint>::const_iterator it;
3187 
3188  for (it = edges_list.begin(); it != edges_list.end(); ++it)
3189  {
3190  vpDisplay::displayPoint(I, *it, color);
3191  }
3192 }
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:623
Definition of the vpMatrix class.
Definition: vpMatrix.h:96
double m02
Definition: vpDot2.h:424
double getTop() const
Definition: vpRect.h:169
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:364
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:1585
double mu02
Definition: vpDot2.h:443
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:868
#define vpERROR_TRACE
Definition: vpDebug.h:379
void setCog(const vpImagePoint &cog)
Definition: vpDot2.h:274
#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:3438
double getSurface() const
Definition: vpDot2.cpp:643
Class to define colors available for display functionnalities.
Definition: vpColor.h:123
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:305
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:653
double get_u() const
Definition: vpImagePoint.h:239
double m11
Definition: vpDot2.h:408
double getHeight() const
Definition: vpDot2.cpp:633
void kill()
Destroy the list.
Definition: vpList.h:694
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:675
double getRight() const
Definition: vpRect.h:162
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:692
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:150
double m01
Definition: vpDot2.h:400
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:440
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:663
void setSurface(const double &surface)
Definition: vpDot2.cpp:743
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:185
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:764
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:433
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:685
void set_u(const double u)
Definition: vpImagePoint.h:203
double m20
Definition: vpDot2.h:415
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:3511
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:2201
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:222
void setComputeMoments(const bool activate)
Definition: vpDot2.h:291
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:335
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:839
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:197
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:348
void setWidth(const double &width)
Definition: vpDot2.cpp:713
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:3115
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:794
double getMeanGrayLevel()
Definition: vpDot2.h:240
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:241
void setHeight(const double &height)
Definition: vpDot2.cpp:728
double m10
Definition: vpDot2.h:392
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:438
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:384
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:157
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:230
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:3008
void setGraphics(const bool activate)
Definition: vpDot2.h:329
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
virtual ~vpDot2()
Definition: vpDot2.cpp:182
static const vpColor blue
Definition: vpColor.h:171