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