Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
vpDot2.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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 = computeParameters(I, cog.get_u(), cog.get_v());
482 
483  if (found) {
484  // test if the found dot is valid (ie similar to the previous one)
485  found = isValid( I, wantedDot);
486  if (! found) {
487  *this = wantedDot;
488  //std::cout << "The found dot is not valid" << std::endl;
489  }
490  }
491 
492  if (! found) {
493  // vpDEBUG_TRACE(0, "Search the dot in a biggest window around the last position");
494  // vpDEBUG_TRACE(0, "Bad computed dot: ");
495  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
496  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
497 
498  // if estimation was wrong (get an error tracking), look for the dot
499  // closest from the estimation,
500  // i.e. search for dots in an a region of interest around the this dot and get the first
501  // element in the area.
502 
503  // first get the size of the search window from the dot size
504  double searchWindowWidth, searchWindowHeight;
505  //if( getWidth() == 0 || getHeight() == 0 )
506  if( std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() || std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon() )
507  {
508  searchWindowWidth = 80.;
509  searchWindowHeight = 80.;
510  }
511  else
512  {
513  searchWindowWidth = getWidth() * 5;
514  searchWindowHeight = getHeight() * 5;
515  }
516  std::list<vpDot2> candidates;
517  searchDotsInArea( I,
518  (int)(this->cog.get_u()-searchWindowWidth /2.0),
519  (int)(this->cog.get_v()-searchWindowHeight/2.0),
520  (unsigned int)searchWindowWidth,
521  (unsigned int)searchWindowHeight,
522  candidates);
523 
524  // if the vector is empty, that mean we didn't find any candidate
525  // in the area, return an error tracking.
526  if( candidates.empty() )
527  {
528  //vpERROR_TRACE("No dot was found") ;
530  "No dot was found")) ;
531  }
532 
533  // otherwise we've got our dot, update this dot's parameters
534  vpDot2 movingDot = candidates.front();
535 
536  setCog( movingDot.getCog() );
537  setArea( movingDot.getArea() );
538  setWidth( movingDot.getWidth() );
539  setHeight( movingDot.getHeight() );
540 
541  // Update the moments
542  m00 = movingDot.m00;
543  m01 = movingDot.m01;
544  m10 = movingDot.m10;
545  m11 = movingDot.m11;
546  m20 = movingDot.m20;
547  m02 = movingDot.m02;
548 
549  // Update the bounding box
550  bbox_u_min = movingDot.bbox_u_min;
551  bbox_u_max = movingDot.bbox_u_max;
552  bbox_v_min = movingDot.bbox_v_min;
553  bbox_v_max = movingDot.bbox_v_max;
554  }
555  // else {
556  // // test if the found dot is valid,
557  // if( ! isValid( I, wantedDot ) ) {
558  // *this = wantedDot;
559  // vpERROR_TRACE("The found dot is invalid:",
560  // "- could be a problem of size (width or height) or "
561  // " surface (number of pixels) which differ too much "
562  // " to the previous one "
563  // "- or a problem of the shape which is not ellipsoid if "
564  // " use setEllipsoidShapePrecision(double ellipsoidShapePrecision) "
565  // " which is the default case. "
566  // " To track a non ellipsoid shape use setEllipsoidShapePrecision(0)") ;
567  // throw(vpTrackingException(vpTrackingException::featureLostError,
568  // "The found dot is invalid")) ;
569  // }
570  // }
571 
572  // if this dot is partially out of the image, return an error tracking.
573  if( !isInImage( I ) )
574  {
575  //vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
577  "The center of gravity of the dot is not in the image")) ;
578  }
579 
580  // Get dots center of gravity
581  // unsigned int u = (unsigned int) this->cog.get_u();
582  // unsigned int v = (unsigned int) this->cog.get_v();
583  // Updates the min and max gray levels for the next iteration
584  // double Ip = pow((double)I[v][u]/255,1/gamma);
585  double Ip = pow(getMeanGrayLevel()/255,1/gamma);
586  //printf("current value of gray level center : %i\n", I[v][u]);
587 
588  //getMeanGrayLevel(I);
589  if(Ip - (1 - grayLevelPrecision)<0){
590  gray_level_min = 0 ;
591  }
592  else{
593  gray_level_min = (unsigned int) (255*pow(Ip - (1 - grayLevelPrecision),gamma));
594  if (gray_level_min > 255)
595  gray_level_min = 255;
596  }
597  gray_level_max = (unsigned int) (255*pow(Ip + (1 - grayLevelPrecision),gamma));
598  if (gray_level_max > 255)
599  gray_level_max = 255;
600 
601  //printf("%i %i \n",gray_level_max,gray_level_min);
602  if (graphics) {
603  // display a red cross at the center of gravity's location in the image.
604 
605  vpDisplay::displayCross(I, this->cog, 3*thickness+8, vpColor::red, thickness);
606  //vpDisplay::flush(I);
607  }
608 }
609 
628 void
630 {
631  track(I);
632 
633  ip = this->cog;
634 }
635 
637 
643 double vpDot2::getWidth() const
644 {
645  return width;
646 }
647 
653 double vpDot2::getHeight() const
654 {
655  return height;
656 }
657 
663 double vpDot2::getArea() const
664 {
665  return fabs(surface);
666 }
667 
674 {
675  return grayLevelPrecision;
676 }
677 
684 {
685  return sizePrecision;
686 }
687 
696 {
697  return ellipsoidShapePrecision;
698 }
699 
706  return maxSizeSearchDistancePrecision;
707 }
708 
712 double vpDot2::getDistance( const vpDot2& distantDot ) const
713 {
714  vpImagePoint cogDistantDot = distantDot.getCog();
715  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
716  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
717  return sqrt( diff_u*diff_u + diff_v*diff_v );
718 }
719 
720 
722 
723 
733 void vpDot2::setWidth( const double & w )
734 {
735  this->width = w;
736 }
737 
748 void vpDot2::setHeight( const double & h )
749 {
750  this->height = h;
751 }
752 
762 void vpDot2::setArea( const double & a )
763 {
764  this->surface = a;
765 }
766 
783 void vpDot2::setGrayLevelPrecision( const double & precision )
784 {
785  double epsilon = 0.05;
786  if( grayLevelPrecision<epsilon )
787  {
788  this->grayLevelPrecision = epsilon;
789  }
790  else if( grayLevelPrecision>1 )
791  {
792  this->grayLevelPrecision = 1.0;
793  }
794  else
795  {
796  this->grayLevelPrecision = precision;
797  }
798 }
813 void vpDot2::setSizePrecision( const double & precision )
814 {
815  if( sizePrecision<0 )
816  {
817  this->sizePrecision = 0;
818  }
819  else if( sizePrecision>1 )
820  {
821  this->sizePrecision = 1.0;
822  }
823  else
824  {
825  this->sizePrecision = precision;
826  }
827 }
828 
858 void vpDot2::setEllipsoidShapePrecision(const double & precision) {
859 
860  if( ellipsoidShapePrecision<0 )
861  {
862  this->ellipsoidShapePrecision = 0;
863  }
864  else if( ellipsoidShapePrecision>1 )
865  {
866  this->ellipsoidShapePrecision = 1.0;
867  }
868  else
869  {
870  this->ellipsoidShapePrecision = precision;
871  }
872 }
873 
887 void vpDot2::setMaxSizeSearchDistancePrecision( const double & precision )
888 {
889  double epsilon = 0.05;
890  if( maxSizeSearchDistancePrecision<epsilon )
891  {
892  this-> maxSizeSearchDistancePrecision = epsilon;
893  }
894  else if( maxSizeSearchDistancePrecision >1 )
895  {
896  this->maxSizeSearchDistancePrecision = 1.0;
897  }
898  else
899  {
900  this->maxSizeSearchDistancePrecision = precision;
901  }
902 }
903 
912 void
914 {
915  setArea(I, 0, 0, I.getWidth(), I.getHeight());
916 }
917 
930 void
932  int u, int v,
933  unsigned int w, unsigned int h)
934 {
935  unsigned int image_w = I.getWidth();
936  unsigned int image_h = I.getHeight();
937 
938  // Bounds the area to the image
939  if (u < 0) u = 0;
940  else if (u >= (int)image_w) u = (int)image_w - 1;
941  if (v < 0) v = 0;
942  else if (v >= (int)image_h) v = (int)image_h - 1;
943 
944  if (((unsigned int)u + w) > image_w) w = image_w - (unsigned int)u - 1;
945  if (((unsigned int)v + h) > image_h) h = image_h - (unsigned int)v - 1;
946 
947  area.setRect(u, v, w, h);
948 }
949 
957 void
958  vpDot2::setArea(const vpRect & a)
959 {
960  area = a;
961 }
962 
964 
1014 void vpDot2::searchDotsInArea(const vpImage<unsigned char>& I, std::list<vpDot2> &niceDots)
1015 {
1016  searchDotsInArea( I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
1017 }
1018 
1041  int area_u,
1042  int area_v,
1043  unsigned int area_w,
1044  unsigned int area_h,
1045  std::list<vpDot2> &niceDots)
1046 
1047 {
1048  // clear the list of nice dots
1049  niceDots.clear();
1050 
1051  // Fit the input area in the image; we keep only the common part between this
1052  // area and the image.
1053  setArea(I, area_u, area_v, area_w, area_h);
1054 
1055  // compute the size of the search grid
1056  unsigned int gridWidth;
1057  unsigned int gridHeight;
1058  getGridSize( gridWidth, gridHeight );
1059 
1060  if (graphics) {
1061  // Display the area were the dot is search
1062  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
1063  //vpDisplay::flush(I);
1064  }
1065 
1066 #ifdef DEBUG
1068  vpDisplay::flush(I);
1069 #endif
1070  // start the search loop; for all points of the search grid,
1071  // test if the pixel belongs to a valid dot.
1072  // if it is so eventually add it to the vector of valid dots.
1073  std::list<vpDot2> badDotsVector;
1074  std::list<vpDot2>::iterator itnice;
1075  std::list<vpDot2>::iterator itbad;
1076 
1077  vpDot2* dotToTest = NULL;
1078  vpDot2 tmpDot;
1079 
1080  unsigned int area_u_min = (unsigned int) area.getLeft();
1081  unsigned int area_u_max = (unsigned int) area.getRight();
1082  unsigned int area_v_min = (unsigned int) area.getTop();
1083  unsigned int area_v_max = (unsigned int) area.getBottom();
1084 
1085  unsigned int u, v;
1086  vpImagePoint cogTmpDot;
1087 
1088  for( v=area_v_min ; v<area_v_max ; v=v+gridHeight )
1089  {
1090  for( u=area_u_min ; u<area_u_max ; u=u+gridWidth )
1091  {
1092  // if the pixel we're in doesn't have the right color (outside the
1093  // graylevel interval), no need to check further, just get to the
1094  // next grid intersection.
1095  if( !hasGoodLevel(I, u, v) ) continue;
1096 
1097  // Test if an other germ is inside the bounding box of a dot previously
1098  // detected
1099  bool good_germ = true;
1100 
1101  itnice = niceDots.begin();
1102  while( itnice != niceDots.end() && good_germ == true) {
1103  tmpDot = *itnice;
1104 
1105  cogTmpDot = tmpDot.getCog();
1106  double u0 = cogTmpDot.get_u();
1107  double v0 = cogTmpDot.get_v();
1108  double half_w = tmpDot.getWidth() / 2.;
1109  double half_h = tmpDot.getHeight() / 2.;
1110 
1111  if ( u >= (u0-half_w) && u <= (u0+half_w) &&
1112  v >= (v0-half_h) && v <= (v0+half_h) ) {
1113  // Germ is in a previously detected dot
1114  good_germ = false;
1115  }
1116  ++ itnice;
1117  }
1118 
1119  if (! good_germ)
1120  continue;
1121 
1122  // Compute the right border position for this possible germ
1123  unsigned int border_u;
1124  unsigned int border_v;
1125  if(findFirstBorder(I, u, v, border_u, border_v) == false){
1126  // germ is not good.
1127  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1128  u = border_u;
1129  v = border_v;
1130  continue;
1131  }
1132 
1133  itbad = badDotsVector.begin();
1134 #define vpBAD_DOT_VALUE (*itbad)
1135  vpImagePoint cogBadDot;
1136 
1137  while( itbad != badDotsVector.end() && good_germ == true) {
1138  if( (double)u >= vpBAD_DOT_VALUE.bbox_u_min
1139  && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1140  (double)v >= vpBAD_DOT_VALUE.bbox_v_min
1141  && (double)v <= vpBAD_DOT_VALUE.bbox_v_max){
1142  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1143  while (it_edges != ip_edges_list.end() && good_germ == true){
1144  // Test if the germ belong to a previously detected dot:
1145  // - from the germ go right to the border and compare this
1146  // position to the list of pixels of previously detected dots
1147  cogBadDot = *it_edges;
1148  //if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1149  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() )
1150  &&
1151  (std::fabs(v - cogBadDot.get_v()) <= vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v()))*std::numeric_limits<double>::epsilon() )) {
1152  good_germ = false;
1153  }
1154  ++ it_edges;
1155  }
1156  }
1157  ++itbad;
1158  }
1159 #undef vpBAD_DOT_VALUE
1160 
1161  if (! good_germ) {
1162  // Jump all the pixels between v,u and v, dotToTest->getFirstBorder_u()
1163  u = border_u;
1164  v = border_v;
1165  continue;
1166  }
1167 
1168  vpTRACE(4, "Try germ (%d, %d)", u, v);
1169 
1170  vpImagePoint germ;
1171  germ.set_u( u );
1172  germ.set_v( v );
1173 
1174  // otherwise estimate the width, height and surface of the dot we
1175  // created, and test it.
1176  if( dotToTest != NULL ) delete dotToTest;
1177  dotToTest = getInstance();
1178  dotToTest->setCog( germ );
1179  dotToTest->setGrayLevelMin ( getGrayLevelMin() );
1180  dotToTest->setGrayLevelMax ( getGrayLevelMax() );
1182  dotToTest->setSizePrecision( getSizePrecision() );
1183  dotToTest->setGraphics( graphics );
1184  dotToTest->setGraphicsThickness( thickness );
1185  dotToTest->setComputeMoments( true );
1186  dotToTest->setArea( area );
1187  dotToTest->setEllipsoidShapePrecision( ellipsoidShapePrecision );
1188  dotToTest->setEllipsoidBadPointsPercentage( allowedBadPointsPercentage_ );
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 
1302  //
1303  // First, check the width, height and surface of the dot. Those parameters
1304  // must be the same.
1305  //
1306  //if ( (wantedDot.getWidth() != 0)
1307  // && (wantedDot.getHeight() != 0)
1308  // && (wantedDot.getArea() != 0) )
1309  if ( (std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon())
1310  &&
1311  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon())
1312  &&
1313  (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon()) )
1314  // if (size_precision!=0){
1315  {
1316  if (std::fabs(size_precision) > std::numeric_limits<double>::epsilon()){
1317  double epsilon = 0.001;
1318 #ifdef DEBUG
1319  std::cout << "test size precision......................\n";
1320  std::cout << "wanted dot: " << "w=" << wantedDot.getWidth()
1321  << " h=" << wantedDot.getHeight()
1322  << " s=" << wantedDot.getArea()
1323  << " precision=" << size_precision
1324  << " epsilon=" << epsilon << std::endl;
1325  std::cout << "dot found: " << "w=" << getWidth()
1326  << " h=" << getHeight()
1327  << " s=" << getArea() << std::endl;
1328 #endif
1329 
1330  if( ( wantedDot.getWidth()*size_precision-epsilon < getWidth() ) == false )
1331  {
1332  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1333  cog.get_u(), cog.get_v());
1334 #ifdef DEBUG
1335  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1336 #endif
1337  return false;
1338  }
1339 
1340  if( ( getWidth() < wantedDot.getWidth()/(size_precision+epsilon ) )== false )
1341  {
1342  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)",
1343  cog.get_u(), cog.get_v());
1344 #ifdef DEBUG
1345  printf("Bad width %g > %g for dot (%g, %g)\n",
1346  getWidth(), wantedDot.getWidth()/(size_precision+epsilon),
1347  cog.get_u(), cog.get_v());
1348 #endif
1349  return false;
1350  }
1351 
1352  if( ( wantedDot.getHeight()*size_precision-epsilon < getHeight() ) == false )
1353  {
1354  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1355  cog.get_u(), cog.get_v());
1356 #ifdef DEBUG
1357  printf("Bad height %g > %g for dot (%g, %g)\n",
1358  wantedDot.getHeight()*size_precision-epsilon, getHeight(),
1359  cog.get_u(), cog.get_v());
1360 #endif
1361  return false;
1362  }
1363 
1364  if( ( getHeight() < wantedDot.getHeight()/(size_precision+epsilon )) == false )
1365  {
1366  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)",
1367  cog.get_u(), cog.get_v());
1368 #ifdef DEBUG
1369  printf("Bad height %g > %g for dot (%g, %g)\n",
1370  getHeight(), wantedDot.getHeight()/(size_precision+epsilon),
1371  cog.get_u(), cog.get_v());
1372 #endif
1373  return false;
1374  }
1375 
1376  if( ( wantedDot.getArea()*(size_precision*size_precision)-epsilon < getArea() ) == false )
1377  {
1378  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1379  cog.get_u(), cog.get_v());
1380 #ifdef DEBUG
1381  printf("Bad surface %g > %g for dot (%g, %g)\n",
1382  wantedDot.getArea()*(size_precision*size_precision)-epsilon,
1383  getArea(),
1384  cog.get_u(), cog.get_v());
1385 #endif
1386  return false;
1387  }
1388 
1389  if( ( getArea() < wantedDot.getArea()/(size_precision*size_precision+epsilon )) == false )
1390  {
1391  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)",
1392  cog.get_u(), cog.get_v());
1393 #ifdef DEBUG
1394  printf("Bad surface %g < %g for dot (%g, %g)\n",
1395  getArea(), wantedDot.getArea()/(size_precision*size_precision+epsilon),
1396  cog.get_u(), cog.get_v());
1397 #endif
1398  return false;
1399  }
1400  }
1401  }
1402  //
1403  // Now we can proceed to more advanced (and costy) checks.
1404  // First check there is a white (>level) elipse within dot
1405  // Then check the dot is surrounded by a black ellipse.
1406  //
1407  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1408  int nb_bad_points = 0;
1409  int nb_max_bad_points = (int)(nb_point_to_test*allowedBadPointsPercentage_);
1410  double step_angle = 2*M_PI / nb_point_to_test;
1411 
1412  // if (ellipsoidShape_precision != 0 && compute_moment) {
1413  if (std::fabs(ellipsoidShape_precision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1414  // std::cout << "test shape precision......................\n";
1415  // See F. Chaumette. Image moments: a general and useful set of features
1416  // for visual servoing. IEEE Trans. on Robotics, 20(4):713-723, August 2004.
1417 
1418  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1419  // = m11 - m10 * m01 / m00
1420  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1421  // = m20 - m10^2 / m00
1422  // mu02 = m02 - m01^2 / m00
1423  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1424  //
1425  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1426  //
1427  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1428 
1429  //we compute parameters of the estimated ellipse
1430  double tmp1 = (m01*m01 -m10*m10)/m00+(m20-m02);
1431  double tmp2 = m11 -m10*m01/m00 ;
1432  double Sqrt = sqrt(tmp1*tmp1 + 4*tmp2*tmp2);
1433  double a1 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 + Sqrt));
1434  double a2 = sqrt(2/m00*((m20+m02)-(m10*m10+m01*m01)/m00 - Sqrt));
1435  double alpha = 0.5*atan2(2*(m11*m00-m10*m01),
1436  ((m20-m02)*m00-m10*m10+m01*m01));
1437 
1438  // to be able to track small dots, minorize the ellipsoid radius for the
1439  // inner test
1440  a1 -= 1.0;
1441  a2 -= 1.0;
1442 
1443  double innerCoef = ellipsoidShape_precision ;
1444  unsigned int u, v;
1445  double cog_u = this->cog.get_u();
1446  double cog_v = this->cog.get_v();
1447 
1448  vpImagePoint ip;
1449  nb_bad_points = 0;
1450  for( double theta = 0. ; theta<2*M_PI ; theta+= step_angle ) {
1451  u = (unsigned int) (cog_u + innerCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
1452  v = (unsigned int) (cog_v + innerCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
1453  if( ! this->hasGoodLevel( I, u, v) ) {
1454  // vpTRACE("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g)",
1455  // u, v, cog_u, cog_v);
1456 #ifdef DEBUG
1457  printf("Inner cercle pixel (%u, %u) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
1458  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1459 #endif
1460  //return false;
1461  nb_bad_points ++;
1462  }
1463  if (graphics) {
1464  for (unsigned int t=0; t< thickness; t++) {
1465  ip.set_u( u + t );
1466  ip.set_v( v );
1468  }
1469  }
1470 #ifdef DEBUG
1472  vpDisplay::flush(I);
1473 #endif
1474  }
1475  if (nb_bad_points > nb_max_bad_points)
1476  {
1477 #ifdef DEBUG
1478  printf("Inner ellipse has %d bad points. Max allowed is %d\n",
1479  nb_bad_points, nb_max_bad_points);
1480 #endif
1481  return false;
1482  }
1483  // to be able to track small dots, maximize the ellipsoid radius for the
1484  // inner test
1485  a1 += 2.0;
1486  a2 += 2.0;
1487 
1488  double outCoef = 2-ellipsoidShape_precision; //1.6;
1489  nb_bad_points = 0;
1490  for( double theta=0. ; theta<2*M_PI ; theta+= step_angle ) {
1491  u = (unsigned int) (cog_u + outCoef*(a1*cos(alpha)*cos(theta)-a2*sin(alpha)*sin(theta)));
1492  v = (unsigned int) (cog_v + outCoef*(a1*sin(alpha)*cos(theta)+a2*cos(alpha)*sin(theta)));
1493 #ifdef DEBUG
1494  //vpDisplay::displayRectangle(I, area, vpColor::yellow);
1495  vpDisplay::displayCross( I, (int) v, (int) u, 7, vpColor::purple ) ;
1496  vpDisplay::flush(I);
1497 #endif
1498  // If outside the area, continue
1499  if ((double)u < area.getLeft() || (double)u > area.getRight()
1500  || (double)v < area.getTop() || (double)v > area.getBottom()) {
1501  continue;
1502  }
1503  if( ! this->hasReverseLevel( I, u, v ) ) {
1504  // vpTRACE("Outside cercle pixel (%d, %d) has bad level for dot (%g, %g)",
1505  // u, v, cog_u, cog_v);
1506 #ifdef DEBUG
1507  printf("Outside cercle pixel (%u, %u) has bad level for dot (%g, %g): %d not in [%d, %d]\n",
1508  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1509 #endif
1510  nb_bad_points ++;
1511  //return false;
1512  }
1513  if (graphics) {
1514  for(unsigned int t=0; t<thickness; t++) {
1515  ip.set_u( u + t);
1516  ip.set_v( v );
1517 
1519  }
1520  }
1521  }
1522  }
1523  if (nb_bad_points > nb_max_bad_points)
1524  {
1525 #ifdef DEBUG
1526  printf("Outside ellipse has %d bad points. Max allowed is %d\n",
1527  nb_bad_points, nb_max_bad_points);
1528 #endif
1529  return false;
1530  }
1531 
1532  return true;
1533 }
1534 
1535 
1536 
1554 bool vpDot2::hasGoodLevel(const vpImage<unsigned char>& I,
1555  const unsigned int &u,
1556  const unsigned int &v) const
1557 {
1558  if( !isInArea( u, v ) )
1559  return false;
1560 
1561  if( I[v][u] >= gray_level_min && I[v][u] <= gray_level_max)
1562  {
1563  return true;
1564  }
1565  else
1566  {
1567  return false;
1568  }
1569 }
1570 
1571 
1584 bool vpDot2::hasReverseLevel(const vpImage<unsigned char>& I,
1585  const unsigned int &u,
1586  const unsigned int &v) const
1587 {
1588 
1589  if( !isInArea( u, v ) )
1590  return false;
1591 
1592  if( I[v][u] < gray_level_min || I[v][u] > gray_level_max)
1593  {
1594  return true;
1595  }
1596  else
1597  {
1598  return false;
1599  }
1600 }
1601 
1602 
1611 vpDot2* vpDot2::getInstance()
1612 {
1613  return new vpDot2();
1614 }
1615 
1631 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const
1632 {
1633  freeman_chain = direction_list;
1634 }
1635 
1636 
1637 
1638 /******************************************************************************
1639  *
1640  * PRIVATE METHODS
1641  *
1642  ******************************************************************************/
1643 
1644 
1645 
1677 bool vpDot2::computeParameters(const vpImage<unsigned char> &I,
1678  const double &_u,
1679  const double &_v)
1680 {
1681  direction_list.clear();
1682  ip_edges_list.clear();
1683 
1684  double est_u = _u; // estimated
1685  double est_v = _v;
1686 
1687  // if u has default value, set it to the actual center value
1688  //if( est_u == -1.0 )
1689  if( std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u),1.)*std::numeric_limits<double>::epsilon() )
1690  {
1691  est_u = this->cog.get_u();
1692  }
1693 
1694  // if v has default value, set it to the actual center value
1695  //if( est_v == -1.0 )
1696  if( std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v),1.)*std::numeric_limits<double>::epsilon() )
1697  {
1698  est_v = this->cog.get_v();
1699  }
1700 
1701  // if the estimated position of the dot is out of the image, not need to continue,
1702  // return an error tracking
1703  if( !isInArea( (unsigned int) est_u, (unsigned int) est_v ) )
1704  {
1705  vpDEBUG_TRACE(3, "Initial pixel coordinates (%d, %d) for dot tracking are not in the area",
1706  (int) est_u, (int) est_v) ;
1707  return false;
1708  }
1709 
1710  bbox_u_min = (int)I.getWidth();
1711  bbox_u_max = 0;
1712  bbox_v_min = (int)I.getHeight();
1713  bbox_v_max = 0;
1714 
1715  // if the first point doesn't have the right level then there's no point to
1716  // continue.
1717  if( !hasGoodLevel( I, (unsigned int) est_u, (unsigned int) est_v ) )
1718  {
1719  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates",
1720  (int) est_u, (int) est_v) ;
1721  return false;
1722  }
1723 
1724  // find the border
1725 
1726  if(!findFirstBorder(I, (unsigned int) est_u, (unsigned int) est_v,
1727  this->firstBorder_u, this->firstBorder_v)) {
1728 
1729  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates",
1730  (int) est_u, (int) est_v) ;
1731  return false;
1732  }
1733 
1734  unsigned int dir = 6;
1735 
1736  // Determine the first element of the Freeman chain
1737  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
1738  unsigned int firstDir = dir;
1739 
1740  // if we are now out of the image, return an error tracking
1741  if( !isInArea( this->firstBorder_u, this->firstBorder_v ) )
1742  {
1743  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area",
1744  this->firstBorder_u, this->firstBorder_v);
1745  return false;
1746  }
1747 
1748  // store the new direction and dot border coordinates.
1749  direction_list.push_back( dir );
1750  vpImagePoint ip;
1751  ip.set_u( this->firstBorder_u );
1752  ip.set_v( this->firstBorder_v );
1753 
1754  ip_edges_list.push_back( ip );
1755 
1756  int border_u = (int)this->firstBorder_u;
1757  int border_v = (int)this->firstBorder_v;
1758 
1759  // vpTRACE("-----------------------------------------");
1760  // vpTRACE("first border_u: %d border_v: %d dir: %d",
1761  // this->firstBorder_u, this->firstBorder_v,firstDir);
1762  int du, dv;
1763  float dS, dMu, dMv, dMuv, dMu2, dMv2;
1764  m00 = 0.0;
1765  m10 = 0.0;
1766  m01 = 0.0;
1767  m11 = 0.0;
1768  m20 = 0.0;
1769  m02 = 0.0;
1770  // while we didn't come back to the first point, follow the border
1771  do {
1772  // if it was asked, show the border
1773  if (graphics) {
1774  for(int t=0; t< (int)thickness; t++) {
1775  ip.set_u ( border_u + t);
1776  ip.set_v ( border_v );
1777 
1779  }
1780  //vpDisplay::flush(I);
1781  }
1782 #ifdef DEBUG
1783  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1784  vpDisplay::flush(I);
1785 #endif
1786  // Determine the increments for the parameters
1787  computeFreemanParameters(border_u, border_v, dir, du, dv,
1788  dS, // surface
1789  dMu, dMv, // first order moments
1790  dMuv, dMu2, dMv2); // second order moment
1791 
1792  // Update the parameters
1793  border_u += du; // Next position on the border
1794  border_v += dv;
1795  m00 += dS; // enclosed area
1796  m10 += dMu; // First order moment along v axis
1797  m01 += dMv; // First order moment along u axis
1798  if (compute_moment) {
1799  m11 += dMuv; // Second order moment
1800  m20 += dMu2; // Second order moment along v axis
1801  m02 += dMv2; // Second order moment along u axis
1802  }
1803  // if we are now out of the image, return an error tracking
1804  if( !isInArea( (unsigned int)border_u, (unsigned int)border_v ) ) {
1805 
1806  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
1807  // Can Occur on a single pixel dot located on the top border
1808  return false;
1809  }
1810 
1811  // store the new direction and dot border coordinates.
1812 
1813  direction_list.push_back( dir );
1814 
1815  ip.set_u( border_u );
1816  ip.set_v( border_v );
1817  ip_edges_list.push_back( ip );
1818 
1819  // vpDisplay::getClick(I);
1820 
1821  // update the extreme point of the dot.
1822  if( border_v < bbox_v_min ) bbox_v_min = border_v;
1823  if( border_v > bbox_v_max ) bbox_v_max = border_v;
1824  if( border_u < bbox_u_min ) bbox_u_min = border_u;
1825  if( border_u > bbox_u_max ) bbox_u_max = border_u;
1826 
1827  // move around the tracked entity by following the border.
1828  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
1829  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)",
1830  border_u, border_v);
1831  return false;
1832  }
1833 
1834  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v, dir);
1835 
1836  }
1837  while( (getFirstBorder_u() != (unsigned int)border_u
1838  || getFirstBorder_v() != (unsigned int)border_v
1839  || firstDir != dir) &&
1840  isInArea( (unsigned int)border_u, (unsigned int)border_v ) );
1841 
1842 #ifdef VP_DEBUG
1843 #if VP_DEBUG_MODE == 3
1844  vpDisplay::flush(I);
1845 #endif
1846 #endif
1847 
1848  // if the surface is one or zero , the center of gravity wasn't properly
1849  // detected. Return an error tracking.
1850  //if( m00 == 0 || m00 == 1 )
1851  if( std::fabs(m00) <= std::numeric_limits<double>::epsilon()
1852  || std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.)*std::numeric_limits<double>::epsilon() )
1853  {
1854  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
1855  return false;
1856  }
1857  else // compute the center
1858  {
1859  // this magic formula gives the coordinates of the center of gravity
1860  double tmpCenter_u = m10 / m00;
1861  double tmpCenter_v = m01 / m00;
1862 
1863  //Updates the central moments
1864  if (compute_moment)
1865  {
1866  mu11 = m11 - tmpCenter_u*m01;
1867  mu02 = m02 - tmpCenter_v*m01;
1868  mu20 = m20 - tmpCenter_u*m10;
1869  }
1870 
1871 
1872  // check the center is in the image... never know...
1873  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
1874  // (unsigned int)tmpCenter_v ) )
1875  // {
1876  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has not a good in level", tmpCenter_u, tmpCenter_v);
1877  // return false;
1878  // }
1879 
1880  cog.set_u( tmpCenter_u );
1881  cog.set_v( tmpCenter_v );
1882  }
1883 
1884  width = bbox_u_max - bbox_u_min + 1;
1885  height = bbox_v_max - bbox_v_min + 1;
1886  surface = m00;
1887 
1888  computeMeanGrayLevel(I);
1889  return true;
1890 }
1891 
1892 
1908 bool
1909  vpDot2::findFirstBorder(const vpImage<unsigned char> &I,
1910  const unsigned int &u,
1911  const unsigned int &v,
1912  unsigned int &border_u,
1913  unsigned int &border_v)
1914 {
1915  // find the border
1916 
1917  // NOTE:
1918  // from here we use int and not double. This is because we don't have
1919  // rounding problems and it's actually more a trouble than smth else to
1920  // work with double when navigating around the dot.
1921  border_u = u;
1922  border_v = v;
1923  double epsilon =0.001;
1924 
1925 #ifdef DEBUG
1926  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
1927 #endif
1928  while( hasGoodLevel( I, border_u+1, border_v ) &&
1929  border_u < area.getRight()/*I.getWidth()*/ ) {
1930  // if the width of this dot was initialised and we already crossed the dot
1931  // on more than the max possible width, no need to continue, return an
1932  // error tracking
1933  if( getWidth() > 0 && ( border_u - u ) > getWidth()/(getMaxSizeSearchDistancePrecision()+epsilon) ) {
1934  vpDEBUG_TRACE(3, "The found dot (%d, %d, %d) has a greater width than the required one", u, v, border_u);
1935  return false;
1936  }
1937 #ifdef DEBUG
1938  vpDisplay::displayPoint(I, (int) border_v, (int) border_u+1, vpColor::green);
1939  vpDisplay::flush(I);
1940 #endif
1941 
1942  border_u++;
1943  }
1944  return true;
1945 }
1946 
1947 
1966 bool
1967  vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I,
1968  const unsigned int &u,
1969  const unsigned int &v,
1970  unsigned int &element)
1971 {
1972 
1973  if (hasGoodLevel( I, u, v )) {
1974  unsigned int _u = u;
1975  unsigned int _v = v;
1976  // get the point on the right of the point passed in
1977  updateFreemanPosition( _u, _v, (element + 2) %8 );
1978  if (hasGoodLevel( I, _u, _v )) {
1979  element = (element + 2) % 8; // turn right
1980  }
1981  else {
1982  unsigned int _u1 = u;
1983  unsigned int _v1 = v;
1984  updateFreemanPosition( _u1, _v1, (element + 1) %8 );
1985 
1986  if ( hasGoodLevel( I, _u1, _v1 )) {
1987  element = (element + 1) % 8; // turn diag right
1988  }
1989  else {
1990  unsigned int _u2 = u;
1991  unsigned int _v2 = v;
1992  updateFreemanPosition( _u2, _v2, element ); // same direction
1993 
1994  if ( hasGoodLevel( I, _u2, _v2 )) {
1995  //element = element; // keep same dir
1996  }
1997  else {
1998  unsigned int _u3 = u;
1999  unsigned int _v3 = v;
2000  updateFreemanPosition( _u3, _v3, (element + 7) %8 ); // diag left
2001 
2002  if ( hasGoodLevel( I, _u3, _v3 )) {
2003  element = (element + 7) %8; // turn diag left
2004  }
2005  else {
2006  unsigned int _u4 = u;
2007  unsigned int _v4 = v;
2008  updateFreemanPosition( _u4, _v4, (element + 6) %8 ); // left
2009 
2010  if ( hasGoodLevel( I, _u4, _v4 )) {
2011  element = (element + 6) %8 ; // turn left
2012  }
2013  else {
2014  unsigned int _u5 = u;
2015  unsigned int _v5 = v;
2016  updateFreemanPosition( _u5, _v5, (element + 5) %8 ); // left
2017 
2018  if ( hasGoodLevel( I, _u5, _v5 )) {
2019  element = (element + 5) %8 ; // turn diag down
2020  }
2021  else {
2022  unsigned int _u6 = u;
2023  unsigned int _v6 = v;
2024  updateFreemanPosition( _u6, _v6, (element + 4) %8 ); // left
2025 
2026  if ( hasGoodLevel( I, _u6, _v6 )) {
2027  element = (element + 4) %8 ; // turn down
2028  }
2029  else {
2030  unsigned int _u7 = u;
2031  unsigned int _v7 = v;
2032  updateFreemanPosition( _u7, _v7, (element + 3) %8 ); // diag
2033 
2034  if ( hasGoodLevel( I, _u7, _v7 )) {
2035  element = (element + 3) %8 ; // turn diag right down
2036  }
2037  else {
2038  // No neighbor with a good level
2039  //
2040  return false;
2041  }
2042  }
2043  }
2044  }
2045  }
2046  }
2047  }
2048  }
2049  }
2050 
2051  else {
2052  return false;
2053  }
2054 
2055  return true;
2056 
2057 }
2058 
2090 void
2091  vpDot2::computeFreemanParameters(const int &u_p,
2092  const int &v_p,
2093  unsigned int &element,
2094  int &du, int &dv,
2095  float &dS,
2096  float &dMu, float &dMv,
2097  float &dMuv,
2098  float &dMu2, float &dMv2)
2099 {
2100  du = 0;
2101  dv = 0;
2102  dMuv = 0;
2103  dMu2 = 0;
2104  dMv2 = 0;
2105 
2106  /*
2107  3 2 1
2108  \ | /
2109  \|/
2110  4 ------- 0
2111  /|\
2112  / | \
2113  5 6 7
2114  */
2115  switch(element) {
2116  case 0: // go right
2117  du = 1;
2118  dS = (float) v_p;
2119  dMu = 0.0;
2120  dMv = (float)(0.5 * v_p * v_p);
2121  if (compute_moment) {
2122  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
2123  dMu2 = 0;
2124  dMv2 = (float)(1.0/ 3. * v_p * v_p * v_p);
2125  }
2126  break;
2127 
2128  case 1: // go right top
2129  du = 1;
2130  dv = 1;
2131  dS = (float)(v_p + 0.5);
2132  dMu = - (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2133  dMv = (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2134  if (compute_moment) {
2135  float half_u_p = (float)(0.5*u_p);
2136  dMuv = (float)(v_p*v_p*(0.25+half_u_p) + v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2137  dMu2 = (float)(-1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1./12.0);
2138  dMv2 = (float)( 1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1./12.0);
2139  }
2140  break;
2141 
2142  case 2: // go top
2143  dv = 1;
2144  dS = 0.0;
2145  dMu = (float)(- 0.5 * u_p * u_p);
2146  dMv = 0.0;
2147  if (compute_moment) {
2148  dMuv = 0;
2149  dMu2 = (float)(-1.0/ 3. * u_p * u_p * u_p);
2150  dMv2 = 0;
2151  }
2152  break;
2153 
2154  case 3:
2155  du = -1;
2156  dv = 1;
2157  dS = (float)(- v_p - 0.5);
2158  dMu = - (float)(0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2159  dMv = - (float)(0.5 * v_p * ( v_p + 1 ) + 1.0 / 6.0);
2160  if (compute_moment) {
2161  float half_u_p = (float)(0.5*u_p);
2162  dMuv = (float)(v_p*v_p*(0.25-half_u_p) + v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2163  dMu2 = (float)(-1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2164  dMv2 = (float)(-1./3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1./12.0);
2165  }
2166  break;
2167 
2168  case 4:
2169  du = -1;
2170  dS = (float)(- v_p);
2171  dMv = (float)(- 0.5 * v_p * v_p);
2172  dMu = 0.0;
2173  if (compute_moment) {
2174  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2175  dMu2 = 0;
2176  dMv2 = (float)(-1.0/ 3. * v_p * v_p * v_p);
2177  }
2178  break;
2179 
2180  case 5:
2181  du = -1;
2182  dv = -1;
2183  dS = (float)(- v_p + 0.5);
2184  dMu = (float)( 0.5 * u_p * ( u_p - 1 ) + 1.0 / 6.0);
2185  dMv = (float)(- (0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0));
2186  if (compute_moment) {
2187  float half_u_p = (float)(0.5*u_p);
2188  dMuv = (float)(v_p*v_p*(0.25-half_u_p) - v_p*(1./3.-half_u_p) - 1./6.*u_p +0.125);
2189  dMu2 = (float)( 1./3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1./12.0);
2190  dMv2 = (float)(-1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2191  }
2192  break;
2193 
2194  case 6:
2195  dv = -1;
2196  dS = 0.0;
2197  dMu = (float)(0.5 * u_p * u_p);
2198  dMv = 0.0;
2199  if (compute_moment) {
2200  dMuv = 0;
2201  dMu2 = (float)(1.0/ 3. * u_p * u_p * u_p);
2202  dMv2 = 0;
2203  }
2204  break;
2205 
2206  case 7:
2207  du = 1;
2208  dv = -1;
2209  dS = (float)(v_p - 0.5);
2210  dMu = (float)(0.5 * u_p * ( u_p + 1 ) + 1.0 / 6.0);
2211  dMv = (float)(0.5 * v_p * ( v_p - 1 ) + 1.0 / 6.0);
2212  if (compute_moment) {
2213  float half_u_p = (float)(0.5*u_p);
2214  dMuv = (float)(v_p*v_p*(0.25+half_u_p) - v_p*(1./3.+half_u_p) + 1./6.*u_p +0.125);
2215  dMu2 = (float)(1./3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1./12.0);
2216  dMv2 = (float)(1./3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1./12.0);
2217  }
2218  break;
2219  }
2220 }
2221 
2222 
2236 void vpDot2::updateFreemanPosition( unsigned int& u, unsigned int& v,
2237  const unsigned int &dir )
2238 {
2239  switch(dir) {
2240  case 0: u += 1; break;
2241  case 1: u += 1; v += 1; break;
2242  case 2: v += 1; break;
2243  case 3: u -= 1; v += 1; break;
2244  case 4: u -= 1; break;
2245  case 5: u -= 1; v -= 1; break;
2246  case 6: v -= 1; break;
2247  case 7: u += 1; v -= 1; break;
2248  }
2249 }
2250 
2262 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const
2263 {
2264  return isInImage( I, cog);
2265 }
2266 
2278 bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
2279 {
2280  unsigned int h = I.getHeight();
2281  unsigned int w = I.getWidth();
2282  double u = ip.get_u();
2283  double v = ip.get_v();
2284 
2285  if( u < 0 || u >= w ) return false;
2286  if( v < 0 || v >= h ) return false;
2287  return true;
2288 }
2289 
2301 bool vpDot2::isInArea( const unsigned int &u, const unsigned int &v) const
2302 {
2303  unsigned int area_u_min = (unsigned int) area.getLeft();
2304  unsigned int area_u_max = (unsigned int) area.getRight();
2305  unsigned int area_v_min = (unsigned int) area.getTop();
2306  unsigned int area_v_max = (unsigned int) area.getBottom();
2307 
2308  if( u < area_u_min || u > area_u_max ) return false;
2309  if( v < area_v_min || v > area_v_max ) return false;
2310  return true;
2311 }
2312 
2313 
2325 void vpDot2::getGridSize( unsigned int &gridWidth, unsigned int &gridHeight )
2326 {
2327  // first get the research grid width and height Note that
2328  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2329  // contained in the dot. We gent this here if the dot is a perfect disc.
2330  // More accurate criterium to define the grid should be implemented if
2331  // necessary
2332  gridWidth = (unsigned int) (getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2333  gridHeight = (unsigned int) (getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2334 
2335  if( gridWidth == 0 ) gridWidth = 1;
2336  if( gridHeight == 0 ) gridHeight = 1;
2337 }
2338 
2339 
2340 
2353 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char>& I)
2354 {
2355  int cog_u = (int)cog.get_u();
2356  int cog_v = (int)cog.get_v();
2357 
2358  unsigned int sum_value =0;
2359  unsigned int nb_pixels =0;
2360 
2361  for(unsigned int i=(unsigned int)this->bbox_u_min; i <=(unsigned int)this->bbox_u_max ; i++){
2362  unsigned int pixel_gray =(unsigned int) I[(unsigned int)cog_v][i];
2363  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2364  sum_value += pixel_gray;
2365  nb_pixels ++;
2366  }
2367  }
2368  for(unsigned int i=(unsigned int)this->bbox_v_min; i <=(unsigned int)this->bbox_v_max ; i++){
2369  unsigned char pixel_gray =I[i][(unsigned int)cog_u];
2370  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2371  sum_value += pixel_gray;
2372  nb_pixels ++;
2373  }
2374  }
2375  if(nb_pixels < 10){ //could be good to choose the min nb points from area of dot
2376  //add diagonals points to have enough point
2377  int imin,imax;
2378  if( (cog_u - bbox_u_min) > (cog_v - bbox_v_min)){
2379  imin=cog_v - bbox_v_min;
2380  }
2381  else{ imin = cog_u - bbox_u_min;}
2382  if( (bbox_u_max - cog_u) > (bbox_v_max - cog_v)){
2383  imax=bbox_v_max - cog_v;
2384  }
2385  else{ imax = bbox_u_max - cog_u;}
2386  for(int i=-imin; i <=imax ; i++){
2387  unsigned int pixel_gray =(unsigned int) I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2388  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2389  sum_value += pixel_gray;
2390  nb_pixels ++;
2391  }
2392  }
2393 
2394  if( (cog_u - bbox_u_min) > (bbox_v_max - cog_v)){
2395  imin = bbox_v_max - cog_v;
2396  }
2397  else{ imin = cog_u - bbox_u_min;}
2398  if( (bbox_u_max - cog_u) > (cog_v - bbox_v_min)){
2399  imax = cog_v - bbox_v_min;
2400  }
2401  else{ imax = bbox_u_max - cog_u;}
2402 
2403  for(int i=-imin; i <=imax ; i++){
2404  unsigned char pixel_gray =I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2405  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()){
2406  sum_value += pixel_gray;
2407  nb_pixels ++;
2408  }
2409  }
2410  }
2411 
2412  if(nb_pixels== 0){
2413  //should never happen
2415  }
2416  else{
2417  mean_gray_level = sum_value/nb_pixels;
2418  }
2419 }
2420 
2436 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I, vpColor col, bool trackDot)
2437 {
2438  vpMatrix Cogs(n, 2);
2439  vpImagePoint cog;
2440  unsigned int i;
2441  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
2442  if(fromFile)
2443  {
2444  vpMatrix::loadMatrix(dotFile, Cogs);
2445  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
2446  }
2447 
2448  // test number of cogs in file
2449  if(Cogs.getRows() < n)
2450  {
2451  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
2452  fromFile = false;
2453  }
2454 
2455  // read from file and tracks the dots
2456  if(fromFile)
2457  {
2458  try
2459  {
2460  for(i=0;i<n;++i)
2461  {
2462  cog.set_uv(Cogs[i][0], Cogs[i][1]);
2463  dot[i].setGraphics(true);
2464  dot[i].setCog(cog);
2465  if(trackDot)
2466  {
2467  dot[i].initTracking(I,cog);
2468  dot[i].track(I);
2469  vpDisplay::displayCross(I, cog, 10, col);
2470  }
2471  }
2472  }
2473  catch(...)
2474  {
2475  std::cout << "Cannot track dots from file" << std::endl;
2476  fromFile = false;
2477  }
2478  vpDisplay::flush(I);
2479 
2480  // check that dots are far away ones from the other
2481  for(i=0;i<n && fromFile;++i)
2482  {
2483  double d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
2484  for(unsigned int j=0;j<n && fromFile;++j)
2485  if(j!=i)
2486  if(dot[i].getDistance(dot[j]) < d)
2487  {
2488  fromFile = false;
2489  std::cout << "Dots from file seem incoherent" << std::endl;
2490  }
2491  }
2492  }
2493 
2494  if(!fromFile)
2495  {
2496  vpDisplay::display(I);
2497  vpDisplay::flush(I);
2498 
2499  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
2500  for (i = 0; i < n; i++)
2501  {
2502  if(trackDot)
2503  {
2504  dot[i].setGraphics(true);
2505  dot[i].initTracking(I);
2506  cog = dot[i].getCog();
2507  }
2508  else
2509  {
2510  vpDisplay::getClick(I, cog);
2511  dot[i].setCog(cog);
2512  }
2513  Cogs[i][0] = cog.get_u();
2514  Cogs[i][1] = cog.get_v();
2515  vpDisplay::displayCross(I, cog, 10, col);
2516  vpDisplay::flush(I);
2517  }
2518  }
2519 
2520  if (!fromFile && (dotFile != ""))
2521  {
2522  vpMatrix::saveMatrix(dotFile, Cogs);
2523  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
2524  }
2525 
2526  // back to non graphic mode
2527  for(i=0;i<n;++i)
2528  dot[i].setGraphics(false);
2529 
2530  return Cogs;
2531 }
2532 
2542 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I, std::vector<vpImagePoint> &cogs, vpImagePoint* cogStar)
2543 {
2544  unsigned int i;
2545  // tracking
2546  for(i=0;i<n;++i)
2547  {
2548  dot[i].track(I);
2549  cogs.push_back(dot[i].getCog());
2550  }
2551  // trajectories
2552  for(i=n;i<cogs.size();++i)
2553  vpDisplay::displayCircle(I,cogs[i],4,vpColor::green,true);
2554  // initial position
2555  for(i=0;i<n;++i)
2556  vpDisplay::displayCircle(I,cogs[i],4,vpColor::blue,true);
2557  // if exists, desired position
2558  if(cogStar != NULL)
2559  for(i=0;i<n;++i)
2560  {
2561  vpDisplay::displayDotLine(I,cogStar[i],dot[i].getCog(),vpColor::red);
2562  vpDisplay::displayCircle(I,cogStar[i],4,vpColor::red,true);
2563  }
2564  vpDisplay::flush(I);
2565 }
2566 
2582  const std::list<vpImagePoint> &edges_list, vpColor color,
2583  unsigned int thickness)
2584 {
2585  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
2586  std::list<vpImagePoint>::const_iterator it;
2587 
2588  for (it = edges_list.begin(); it != edges_list.end(); ++it)
2589  {
2590  vpDisplay::displayPoint(I, *it, color);
2591  }
2592 }
2593 
2609  const std::list<vpImagePoint> &edges_list, vpColor color,
2610  unsigned int thickness)
2611 {
2612  vpDisplay::displayCross(I, cog, 3*thickness+8, color, thickness);
2613  std::list<vpImagePoint>::const_iterator it;
2614 
2615  for (it = edges_list.begin(); it != edges_list.end(); ++it)
2616  {
2617  vpDisplay::displayPoint(I, *it, color);
2618  }
2619 }
2620 
2626 VISP_EXPORT std::ostream& operator<< (std::ostream& os, vpDot2& d) {
2627  return (os << "(" << d.getCog() << ")" ) ;
2628 }
double getWidth() const
Definition: vpDot2.cpp:643
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:97
double m02
Definition: vpDot2.h:410
double getTop() const
Definition: vpRect.h:178
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:351
double get_v() const
Definition: vpImagePoint.h:268
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:1040
void getFreemanChain(std::list< unsigned int > &freeman_chain) const
Definition: vpDot2.cpp:1631
static bool loadMatrix(const std::string &filename, vpArray2D< double > &M, const bool binary=false, char *header=NULL)
Definition: vpMatrix.h:523
double mu02
Definition: vpDot2.h:429
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
double get_i() const
Definition: vpImagePoint.h:199
unsigned int getWidth() const
Definition: vpImage.h:226
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:887
Class to define colors available for display functionnalities.
Definition: vpColor.h:121
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:292
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:673
vpDot2 & operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:154
double get_u() const
Definition: vpImagePoint.h:257
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:261
error that can be emited by ViSP classes.
Definition: vpException.h:73
double m11
Definition: vpDot2.h:394
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
double getHeight() const
Definition: vpDot2.cpp:653
double getArea() const
Definition: vpDot2.cpp:663
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:695
double getRight() const
Definition: vpRect.h:165
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:712
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:125
double m01
Definition: vpDot2.h:386
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:461
static void flush(const vpImage< unsigned char > &I)
double get_j() const
Definition: vpImagePoint.h:210
double getSizePrecision() const
Definition: vpDot2.cpp:683
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:140
vpImagePoint getCog() const
Definition: vpDot2.h:161
void setGraphicsThickness(unsigned int t)
Definition: vpDot2.h:322
static bool checkFilename(const char *filename)
Definition: vpIoTools.cpp:508
double getBottom() const
Definition: vpRect.h:100
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:783
Error that can be emited by the vpTracker class and its derivates.
double mu11
Definition: vpDot2.h:419
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:705
void set_u(const double u)
Definition: vpImagePoint.h:221
double m20
Definition: vpDot2.h:401
#define vpTRACE
Definition: vpDebug.h:414
static double sqr(double x)
Definition: vpMath.h:110
static void display(const vpImage< unsigned char > &I)
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:232
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:210
void setComputeMoments(const bool activate)
Definition: vpDot2.h:278
void setArea(const double &area)
Definition: vpDot2.cpp:762
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition: vpArray2D.h:267
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
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:858
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:335
static void displayCircle(const vpImage< unsigned char > &I, const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1)
void setWidth(const double &width)
Definition: vpDot2.cpp:733
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:2542
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:813
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:555
void setHeight(const double &height)
Definition: vpDot2.cpp:748
double m10
Definition: vpDot2.h:378
#define vpDEBUG_TRACE
Definition: vpDebug.h:478
unsigned int getHeight() const
Definition: vpImage.h:175
void set_uv(const double u, const double v)
Definition: vpImagePoint.h:243
double mu20
Definition: vpDot2.h:424
Defines a rectangle in the plane.
Definition: vpRect.h:82
double getMeanGrayLevel() const
Definition: vpDot2.h:228
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:370
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:218
static const vpColor purple
Definition: vpColor.h:174
void setRect(double l, double t, double w, double h)
Definition: vpRect.h:269
double getLeft() const
Definition: vpRect.h:159
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:2436
void setGraphics(const bool activate)
Definition: vpDot2.h:316
static void displayDotLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
virtual ~vpDot2()
Definition: vpDot2.cpp:204
static const vpColor blue
Definition: vpColor.h:169