Visual Servoing Platform  version 3.6.0 under development (2023-09-29)
vpDot2.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Track a white dot.
33  *
34  * Authors:
35  * Anthony Saunier
36  *
37 *****************************************************************************/
38 
44 //#define DEBUG
45 
46 #include <visp3/core/vpDisplay.h>
47 
48 // exception handling
49 #include <visp3/core/vpIoTools.h>
50 #include <visp3/core/vpMath.h>
51 #include <visp3/core/vpTrackingException.h>
52 
53 #include <cmath> // std::fabs
54 #include <iostream>
55 #include <limits> // numeric_limits
56 #include <math.h>
57 #include <visp3/blob/vpDot2.h>
58 
59 /******************************************************************************
60  *
61  * CONSTRUCTORS AND DESTRUCTORS
62  *
63 *****************************************************************************/
69 void vpDot2::init()
70 {
71  cog.set_u(0);
72  cog.set_v(0);
73 
74  width = 0;
75  height = 0;
76  surface = 0;
77  mean_gray_level = 0;
78  gray_level_min = 128;
79  gray_level_max = 255;
80  grayLevelPrecision = 0.80;
81  gamma = 1.5;
82 
83  sizePrecision = 0.65;
84  ellipsoidShapePrecision = 0.65;
85  maxSizeSearchDistancePrecision = 0.65;
87  m00 = m11 = m02 = m20 = m10 = m01 = 0.;
88  mu11 = mu02 = mu20 = 0.;
89 
90  bbox_u_min = bbox_u_max = bbox_v_min = bbox_v_max = 0;
91 
92  firstBorder_u = 0;
93  firstBorder_v = 0;
94 
95  compute_moment = false;
96  graphics = false;
97  thickness = 1;
98 }
99 
104  : m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), cog(), width(0), height(0),
105  surface(0), gray_level_min(128), gray_level_max(255), mean_gray_level(0), grayLevelPrecision(0.8), gamma(1.5),
106  sizePrecision(0.65), ellipsoidShapePrecision(0.65), maxSizeSearchDistancePrecision(0.65),
107  allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(), compute_moment(false), graphics(false),
108  thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0), firstBorder_u(0), firstBorder_v()
109 {
110 }
111 
121  : m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), cog(ip), width(0), height(0),
122  surface(0), gray_level_min(128), gray_level_max(255), mean_gray_level(0), grayLevelPrecision(0.8), gamma(1.5),
123  sizePrecision(0.65), ellipsoidShapePrecision(0.65), maxSizeSearchDistancePrecision(0.65),
124  allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(), compute_moment(false), graphics(false),
125  thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0), firstBorder_u(0), firstBorder_v()
126 {
127 }
128 
132 vpDot2::vpDot2(const vpDot2 &twinDot)
133  : vpTracker(twinDot), m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), cog(),
134  width(0), height(0), surface(0), gray_level_min(128), gray_level_max(255), mean_gray_level(0),
135  grayLevelPrecision(0.8), gamma(1.5), sizePrecision(0.65), ellipsoidShapePrecision(0.65),
136  maxSizeSearchDistancePrecision(0.65), allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(),
137  compute_moment(false), graphics(false), thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0),
138  firstBorder_u(0), firstBorder_v()
139 {
140  *this = twinDot;
141 }
142 
147 {
148  cog = twinDot.cog;
149 
150  width = twinDot.width;
151  height = twinDot.height;
152  surface = twinDot.surface;
153  gray_level_min = twinDot.gray_level_min;
154  gray_level_max = twinDot.gray_level_max;
155  mean_gray_level = twinDot.mean_gray_level;
156  grayLevelPrecision = twinDot.grayLevelPrecision;
157  gamma = twinDot.gamma;
158  ;
159  sizePrecision = twinDot.sizePrecision;
160  ellipsoidShapePrecision = twinDot.ellipsoidShapePrecision;
161  maxSizeSearchDistancePrecision = twinDot.maxSizeSearchDistancePrecision;
162  allowedBadPointsPercentage_ = twinDot.allowedBadPointsPercentage_;
163  area = twinDot.area;
164 
165  direction_list = twinDot.direction_list;
166  ip_edges_list = twinDot.ip_edges_list;
167 
168  compute_moment = twinDot.compute_moment;
169  graphics = twinDot.graphics;
170  thickness = twinDot.thickness;
171 
172  bbox_u_min = twinDot.bbox_u_min;
173  bbox_u_max = twinDot.bbox_u_max;
174  bbox_v_min = twinDot.bbox_v_min;
175  bbox_v_max = twinDot.bbox_v_max;
176 
177  firstBorder_u = twinDot.firstBorder_u;
178  firstBorder_v = twinDot.firstBorder_v;
179 
180  m00 = twinDot.m00;
181  m01 = twinDot.m01;
182  m11 = twinDot.m11;
183  m10 = twinDot.m10;
184  m02 = twinDot.m02;
185  m20 = twinDot.m20;
186 
187  mu11 = twinDot.mu11;
188  mu20 = twinDot.mu20;
189  mu02 = twinDot.mu02;
190 
191  return (*this);
192 }
193 
198 
199 /******************************************************************************
200  *
201  * PUBLIC METHODS
202  *****************************************************************************/
203 
211 void vpDot2::display(const vpImage<unsigned char> &I, vpColor color, unsigned int t) const
212 {
213  vpDisplay::displayCross(I, cog, 3 * t + 8, color, t);
214  std::list<vpImagePoint>::const_iterator it;
215 
216  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it) {
217  vpDisplay::displayPoint(I, *it, color);
218  }
219 }
220 
252 void vpDot2::initTracking(const vpImage<unsigned char> &I, unsigned int size)
253 {
254  while (vpDisplay::getClick(I, cog) != true) {
255  }
256 
257  unsigned int i = (unsigned int)cog.get_i();
258  unsigned int j = (unsigned int)cog.get_j();
259 
260  double Ip = pow((double)I[i][j] / 255, 1 / gamma);
261 
262  if (Ip - (1 - grayLevelPrecision) < 0) {
263  gray_level_min = 0;
264  } else {
265  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
266  if (gray_level_min > 255)
267  gray_level_min = 255;
268  }
269  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
270  if (gray_level_max > 255)
271  gray_level_max = 255;
272 
273  setWidth(size);
274  setHeight(size);
275 
276  try {
277  track(I);
278  } catch (const vpException &e) {
279  // vpERROR_TRACE("Error caught") ;
280  throw(e);
281  }
282 }
283 
311 void vpDot2::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip, unsigned int size)
312 {
313  cog = ip;
314 
315  unsigned int i = (unsigned int)cog.get_i();
316  unsigned int j = (unsigned int)cog.get_j();
317 
318  double Ip = pow((double)I[i][j] / 255, 1 / gamma);
319 
320  if (Ip - (1 - grayLevelPrecision) < 0) {
321  gray_level_min = 0;
322  } else {
323  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
324  if (gray_level_min > 255)
325  gray_level_min = 255;
326  }
327  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
328  if (gray_level_max > 255)
329  gray_level_max = 255;
330 
331  setWidth(size);
332  setHeight(size);
333 
334  try {
335  track(I);
336  } catch (const vpException &e) {
337  // vpERROR_TRACE("Error caught") ;
338  throw(e);
339  }
340 }
341 
381 void vpDot2::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip, unsigned int gray_lvl_min,
382  unsigned int gray_lvl_max, unsigned int size)
383 {
384  cog = ip;
385 
386  this->gray_level_min = gray_lvl_min;
387  this->gray_level_max = gray_lvl_max;
388 
389  setWidth(size);
390  setHeight(size);
391 
392  try {
393  track(I);
394  } catch (const vpException &e) {
395  // vpERROR_TRACE("Error caught") ;
396  throw(e);
397  }
398 }
399 
441 void vpDot2::track(const vpImage<unsigned char> &I, bool canMakeTheWindowGrow)
442 {
443  m00 = m11 = m02 = m20 = m10 = m01 = 0;
444 
445  // First, we will estimate the position of the tracked point
446 
447  // Set the search area to the entire image
448  setArea(I);
449 
450  // create a copy of the dot to search
451  // This copy can be saw as the previous dot used to check if the current one
452  // found with computeParameters() is similar to the previous one (see
453  // isValid() function). If the found dot is not similar (or valid), we use
454  // this copy to set the current found dot to the previous one (see below).
455  vpDot2 wantedDot(*this);
456 
457  // vpDEBUG_TRACE(0, "Previous dot: ");
458  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
459  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
460  bool found = computeParameters(I, cog.get_u(), cog.get_v());
461 
462  if (found) {
463  // test if the found dot is valid (ie similar to the previous one)
464  found = isValid(I, wantedDot);
465  if (!found) {
466  *this = wantedDot;
467  // std::cout << "The found dot is not valid" << std::endl;
468  }
469  }
470 
471  if (!found) {
472  // vpDEBUG_TRACE(0, "Search the dot in a biggest window around the
473  // last position"); vpDEBUG_TRACE(0, "Bad computed dot: ");
474  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
475  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
476 
477  // if estimation was wrong (get an error tracking), look for the dot
478  // closest from the estimation,
479  // i.e. search for dots in an a region of interest around the this dot and
480  // get the first element in the area.
481 
482  // first get the size of the search window from the dot size
483  double searchWindowWidth = 0.0, searchWindowHeight = 0.0;
484  // if( getWidth() == 0 || getHeight() == 0 )
485  if (std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() ||
486  std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon()) {
487  searchWindowWidth = 80.;
488  searchWindowHeight = 80.;
489  } else if (canMakeTheWindowGrow) {
490  searchWindowWidth = getWidth() * 5;
491  searchWindowHeight = getHeight() * 5;
492  } else {
493  searchWindowWidth = getWidth();
494  searchWindowHeight = getHeight();
495  }
496 
497  std::list<vpDot2> candidates;
498  searchDotsInArea(I, (int)(this->cog.get_u() - searchWindowWidth / 2.0),
499  (int)(this->cog.get_v() - searchWindowHeight / 2.0), (unsigned int)searchWindowWidth,
500  (unsigned int)searchWindowHeight, candidates);
501 
502  // if the vector is empty, that mean we didn't find any candidate
503  // in the area, return an error tracking.
504  if (candidates.empty()) {
505  // vpERROR_TRACE("No dot was found") ;
507  }
508 
509  // otherwise we've got our dot, update this dot's parameters
510  vpDot2 movingDot = candidates.front();
511 
512  setCog(movingDot.getCog());
513  setArea(movingDot.getArea());
514  setWidth(movingDot.getWidth());
515  setHeight(movingDot.getHeight());
516 
517  // Update the moments
518  m00 = movingDot.m00;
519  m01 = movingDot.m01;
520  m10 = movingDot.m10;
521  m11 = movingDot.m11;
522  m20 = movingDot.m20;
523  m02 = movingDot.m02;
524 
525  // Update the bounding box
526  bbox_u_min = movingDot.bbox_u_min;
527  bbox_u_max = movingDot.bbox_u_max;
528  bbox_v_min = movingDot.bbox_v_min;
529  bbox_v_max = movingDot.bbox_v_max;
530  }
531 
532  // if this dot is partially out of the image, return an error tracking.
533  if (!isInImage(I)) {
534  // vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
536  "The center of gravity of the dot is not in the image"));
537  }
538 
539  // Get dots center of gravity
540  // unsigned int u = (unsigned int) this->cog.get_u();
541  // unsigned int v = (unsigned int) this->cog.get_v();
542  // Updates the min and max gray levels for the next iteration
543  // double Ip = pow((double)I[v][u]/255,1/gamma);
544  double Ip = pow(getMeanGrayLevel() / 255, 1 / gamma);
545  // printf("current value of gray level center : %i\n", I[v][u]);
546 
547  // getMeanGrayLevel(I);
548  if (Ip - (1 - grayLevelPrecision) < 0) {
549  gray_level_min = 0;
550  } else {
551  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
552  if (gray_level_min > 255)
553  gray_level_min = 255;
554  }
555  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
556  if (gray_level_max > 255)
557  gray_level_max = 255;
558 
559  // printf("%i %i \n",gray_level_max,gray_level_min);
560  if (graphics) {
561  // display a red cross at the center of gravity's location in the image.
562 
563  vpDisplay::displayCross(I, this->cog, 3 * thickness + 8, vpColor::red, thickness);
564  // vpDisplay::flush(I);
565  }
566 }
567 
590 void vpDot2::track(const vpImage<unsigned char> &I, vpImagePoint &ip, bool canMakeTheWindowGrow)
591 {
592  track(I, canMakeTheWindowGrow);
593 
594  ip = this->cog;
595 }
596 
599 
605 double vpDot2::getWidth() const { return width; }
606 
612 double vpDot2::getHeight() const { return height; }
613 
619 double vpDot2::getArea() const { return fabs(surface); }
620 
626 double vpDot2::getGrayLevelPrecision() const { return grayLevelPrecision; }
627 
633 double vpDot2::getSizePrecision() const { return sizePrecision; }
634 
642 double vpDot2::getEllipsoidShapePrecision() const { return ellipsoidShapePrecision; }
643 
650 double vpDot2::getMaxSizeSearchDistancePrecision() const { return maxSizeSearchDistancePrecision; }
651 
655 double vpDot2::getDistance(const vpDot2 &distantDot) const
656 {
657  vpImagePoint cogDistantDot = distantDot.getCog();
658  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
659  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
660  return sqrt(diff_u * diff_u + diff_v * diff_v);
661 }
662 
664 
674 void vpDot2::setWidth(const double &w) { this->width = w; }
675 
686 void vpDot2::setHeight(const double &h) { this->height = h; }
687 
698 void vpDot2::setArea(const double &a) { this->surface = a; }
699 
717 void vpDot2::setGrayLevelPrecision(const double &precision)
718 {
719  double epsilon = 0.05;
720  if (grayLevelPrecision < epsilon) {
721  this->grayLevelPrecision = epsilon;
722  } else if (grayLevelPrecision > 1) {
723  this->grayLevelPrecision = 1.0;
724  } else {
725  this->grayLevelPrecision = precision;
726  }
727 }
745 void vpDot2::setSizePrecision(const double &precision)
746 {
747  if (sizePrecision < 0) {
748  this->sizePrecision = 0;
749  } else if (sizePrecision > 1) {
750  this->sizePrecision = 1.0;
751  } else {
752  this->sizePrecision = precision;
753  }
754 }
755 
788 void vpDot2::setEllipsoidShapePrecision(const double &precision)
789 {
790 
791  if (ellipsoidShapePrecision < 0) {
792  this->ellipsoidShapePrecision = 0;
793  } else if (ellipsoidShapePrecision > 1) {
794  this->ellipsoidShapePrecision = 1.0;
795  } else {
796  this->ellipsoidShapePrecision = precision;
797  }
798 }
799 
815 void vpDot2::setMaxSizeSearchDistancePrecision(const double &precision)
816 {
817  double epsilon = 0.05;
818  if (maxSizeSearchDistancePrecision < epsilon) {
819  this->maxSizeSearchDistancePrecision = epsilon;
820  } else if (maxSizeSearchDistancePrecision > 1) {
821  this->maxSizeSearchDistancePrecision = 1.0;
822  } else {
823  this->maxSizeSearchDistancePrecision = precision;
824  }
825 }
826 
835 void vpDot2::setArea(const vpImage<unsigned char> &I) { setArea(I, 0, 0, I.getWidth(), I.getHeight()); }
836 
849 void vpDot2::setArea(const vpImage<unsigned char> &I, int u, int v, unsigned int w, unsigned int h)
850 {
851  unsigned int image_w = I.getWidth();
852  unsigned int image_h = I.getHeight();
853 
854  // Bounds the area to the image
855  if (u < 0)
856  u = 0;
857  else if (u >= (int)image_w)
858  u = (int)image_w - 1;
859  if (v < 0)
860  v = 0;
861  else if (v >= (int)image_h)
862  v = (int)image_h - 1;
863 
864  if (((unsigned int)u + w) > image_w)
865  w = image_w - (unsigned int)u - 1;
866  if (((unsigned int)v + h) > image_h)
867  h = image_h - (unsigned int)v - 1;
868 
869  area.setRect(u, v, w, h);
870 }
871 
879 void vpDot2::setArea(const vpRect &a) { area = a; }
880 
882 
934 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, std::list<vpDot2> &niceDots)
935 {
936  searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
937 }
938 
961 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, int area_u, int area_v, unsigned int area_w,
962  unsigned int area_h, std::list<vpDot2> &niceDots)
963 
964 {
965  // clear the list of nice dots
966  niceDots.clear();
967 
968  // Fit the input area in the image; we keep only the common part between
969  // this area and the image.
970  setArea(I, area_u, area_v, area_w, area_h);
971 
972  // compute the size of the search grid
973  unsigned int gridWidth;
974  unsigned int gridHeight;
975  getGridSize(gridWidth, gridHeight);
976 
977  if (graphics) {
978  // Display the area were the dot is search
979  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
980  // vpDisplay::flush(I);
981  }
982 
983 #ifdef DEBUG
985  vpDisplay::flush(I);
986 #endif
987  // start the search loop; for all points of the search grid,
988  // test if the pixel belongs to a valid dot.
989  // if it is so eventually add it to the vector of valid dots.
990  std::list<vpDot2> badDotsVector;
991  std::list<vpDot2>::iterator itnice;
992  std::list<vpDot2>::iterator itbad;
993 
994  vpDot2 *dotToTest = NULL;
995  vpDot2 tmpDot;
996 
997  unsigned int area_u_min = (unsigned int)area.getLeft();
998  unsigned int area_u_max = (unsigned int)area.getRight();
999  unsigned int area_v_min = (unsigned int)area.getTop();
1000  unsigned int area_v_max = (unsigned int)area.getBottom();
1001 
1002  unsigned int u, v;
1003  vpImagePoint cogTmpDot;
1004 
1005  for (v = area_v_min; v < area_v_max; v = v + gridHeight) {
1006  for (u = area_u_min; u < area_u_max; u = u + gridWidth) {
1007  // if the pixel we're in doesn't have the right color (outside the
1008  // graylevel interval), no need to check further, just get to the
1009  // next grid intersection.
1010  if (!hasGoodLevel(I, u, v))
1011  continue;
1012 
1013  // Test if an other germ is inside the bounding box of a dot previously
1014  // detected
1015  bool good_germ = true;
1016 
1017  itnice = niceDots.begin();
1018  while (itnice != niceDots.end() && good_germ == true) {
1019  tmpDot = *itnice;
1020 
1021  cogTmpDot = tmpDot.getCog();
1022  double u0 = cogTmpDot.get_u();
1023  double v0 = cogTmpDot.get_v();
1024  double half_w = tmpDot.getWidth() / 2.;
1025  double half_h = tmpDot.getHeight() / 2.;
1026 
1027  if (u >= (u0 - half_w) && u <= (u0 + half_w) && v >= (v0 - half_h) && v <= (v0 + half_h)) {
1028  // Germ is in a previously detected dot
1029  good_germ = false;
1030  }
1031  ++itnice;
1032  }
1033 
1034  if (!good_germ)
1035  continue;
1036 
1037  // Compute the right border position for this possible germ
1038  unsigned int border_u;
1039  unsigned int border_v;
1040  if (findFirstBorder(I, u, v, border_u, border_v) == false) {
1041  // germ is not good.
1042  // Jump all the pixels between v,u and v,
1043  // dotToTest->getFirstBorder_u()
1044  u = border_u;
1045  v = border_v;
1046  continue;
1047  }
1048 
1049  itbad = badDotsVector.begin();
1050 #define vpBAD_DOT_VALUE (*itbad)
1051  vpImagePoint cogBadDot;
1052 
1053  while (itbad != badDotsVector.end() && good_germ == true) {
1054  if ((double)u >= vpBAD_DOT_VALUE.bbox_u_min && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1055  (double)v >= vpBAD_DOT_VALUE.bbox_v_min && (double)v <= vpBAD_DOT_VALUE.bbox_v_max) {
1056  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1057  while (it_edges != ip_edges_list.end() && good_germ == true) {
1058  // Test if the germ belong to a previously detected dot:
1059  // - from the germ go right to the border and compare this
1060  // position to the list of pixels of previously detected dots
1061  cogBadDot = *it_edges;
1062  // if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1063  if ((std::fabs(border_u - cogBadDot.get_u()) <=
1064  vpMath::maximum(std::fabs((double)border_u), std::fabs(cogBadDot.get_u())) *
1065  std::numeric_limits<double>::epsilon()) &&
1066  (std::fabs(v - cogBadDot.get_v()) <=
1067  vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v())) *
1068  std::numeric_limits<double>::epsilon())) {
1069  good_germ = false;
1070  }
1071  ++it_edges;
1072  }
1073  }
1074  ++itbad;
1075  }
1076 #undef vpBAD_DOT_VALUE
1077 
1078  if (!good_germ) {
1079  // Jump all the pixels between v,u and v,
1080  // dotToTest->getFirstBorder_u()
1081  u = border_u;
1082  v = border_v;
1083  continue;
1084  }
1085 
1086  vpTRACE(4, "Try germ (%d, %d)", u, v);
1087 
1088  vpImagePoint germ;
1089  germ.set_u(u);
1090  germ.set_v(v);
1091 
1092  // otherwise estimate the width, height and surface of the dot we
1093  // created, and test it.
1094  if (dotToTest != NULL)
1095  delete dotToTest;
1096  dotToTest = getInstance();
1097  dotToTest->setCog(germ);
1098  dotToTest->setGrayLevelMin(getGrayLevelMin());
1099  dotToTest->setGrayLevelMax(getGrayLevelMax());
1101  dotToTest->setSizePrecision(getSizePrecision());
1102  dotToTest->setGraphics(graphics);
1103  dotToTest->setGraphicsThickness(thickness);
1104  dotToTest->setComputeMoments(true);
1105  dotToTest->setArea(area);
1106  dotToTest->setEllipsoidShapePrecision(ellipsoidShapePrecision);
1107  dotToTest->setEllipsoidBadPointsPercentage(allowedBadPointsPercentage_);
1108 
1109  // first compute the parameters of the dot.
1110  // if for some reasons this caused an error tracking
1111  // (dot partially out of the image...), check the next intersection
1112  if (dotToTest->computeParameters(I) == false) {
1113  // Jump all the pixels between v,u and v,
1114  // dotToTest->getFirstBorder_u()
1115  u = border_u;
1116  v = border_v;
1117  continue;
1118  }
1119  // if the dot to test is valid,
1120  if (dotToTest->isValid(I, *this)) {
1121  vpImagePoint cogDotToTest = dotToTest->getCog();
1122  // Compute the distance to the center. The center used here is not the
1123  // area center available by area.getCenter(area_center_u,
1124  // area_center_v) but the center of the input area which may be
1125  // partially outside the image.
1126 
1127  double area_center_u = area_u + area_w / 2.0 - 0.5;
1128  double area_center_v = area_v + area_h / 2.0 - 0.5;
1129 
1130  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1131  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1132  double thisDist = sqrt(thisDiff_u * thisDiff_u + thisDiff_v * thisDiff_v);
1133 
1134  bool stopLoop = false;
1135  itnice = niceDots.begin();
1136 
1137  while (itnice != niceDots.end() && stopLoop == false) {
1138  tmpDot = *itnice;
1139 
1140  // double epsilon = 0.001; // detecte +sieurs points
1141  double epsilon = 3.0;
1142  // if the center of the dot is the same than the current
1143  // don't add it, test the next point of the grid
1144  cogTmpDot = tmpDot.getCog();
1145 
1146  if (fabs(cogTmpDot.get_u() - cogDotToTest.get_u()) < epsilon &&
1147  fabs(cogTmpDot.get_v() - cogDotToTest.get_v()) < epsilon) {
1148  stopLoop = true;
1149  // Jump all the pixels between v,u and v,
1150  // tmpDot->getFirstBorder_u()
1151  u = border_u;
1152  v = border_v;
1153  continue;
1154  }
1155 
1156  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1157  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1158  double otherDist = sqrt(otherDiff_u * otherDiff_u + otherDiff_v * otherDiff_v);
1159 
1160  // if the distance of the curent vector element to the center
1161  // is greater than the distance of this dot to the center,
1162  // then add this dot before the current vector element.
1163  if (otherDist > thisDist) {
1164  niceDots.insert(itnice, *dotToTest);
1165  ++itnice;
1166  stopLoop = true;
1167  // Jump all the pixels between v,u and v,
1168  // tmpDot->getFirstBorder_u()
1169  u = border_u;
1170  v = border_v;
1171  continue;
1172  }
1173  ++itnice;
1174  }
1175  vpTRACE(4, "End while (%d, %d)", u, v);
1176 
1177  // if we reached the end of the vector without finding the dot
1178  // or inserting it, insert it now.
1179  if (itnice == niceDots.end() && stopLoop == false) {
1180  niceDots.push_back(*dotToTest);
1181  }
1182  } else {
1183  // Store bad dots
1184  badDotsVector.push_front(*dotToTest);
1185  }
1186  }
1187  }
1188  if (dotToTest != NULL)
1189  delete dotToTest;
1190 }
1191 
1212 bool vpDot2::isValid(const vpImage<unsigned char> &I, const vpDot2 &wantedDot)
1213 {
1214  double size_precision = wantedDot.getSizePrecision();
1215  double ellipsoidShape_precision = wantedDot.getEllipsoidShapePrecision();
1216 
1217  //
1218  // First, check the width, height and surface of the dot. Those parameters
1219  // must be the same.
1220  //
1221  // if ( (wantedDot.getWidth() != 0)
1222  // && (wantedDot.getHeight() != 0)
1223  // && (wantedDot.getArea() != 0) )
1224  if ((std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon()) &&
1225  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon()) &&
1226  (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon()))
1227  // if (size_precision!=0){
1228  {
1229  if (std::fabs(size_precision) > std::numeric_limits<double>::epsilon()) {
1230  double epsilon = 0.001;
1231 #ifdef DEBUG
1232  std::cout << "test size precision......................\n";
1233  std::cout << "wanted dot: "
1234  << "w=" << wantedDot.getWidth() << " h=" << wantedDot.getHeight() << " s=" << wantedDot.getArea()
1235  << " precision=" << size_precision << " epsilon=" << epsilon << std::endl;
1236  std::cout << "dot found: "
1237  << "w=" << getWidth() << " h=" << getHeight() << " s=" << getArea() << std::endl;
1238 #endif
1239 
1240  if ((wantedDot.getWidth() * size_precision - epsilon < getWidth()) == false) {
1241  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1242 #ifdef DEBUG
1243  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1244 #endif
1245  return false;
1246  }
1247 
1248  if ((getWidth() < wantedDot.getWidth() / (size_precision + epsilon)) == false) {
1249  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1250 #ifdef DEBUG
1251  printf("Bad width %g > %g for dot (%g, %g)\n", getWidth(), wantedDot.getWidth() / (size_precision + epsilon),
1252  cog.get_u(), cog.get_v());
1253 #endif
1254  return false;
1255  }
1256 
1257  if ((wantedDot.getHeight() * size_precision - epsilon < getHeight()) == false) {
1258  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1259 #ifdef DEBUG
1260  printf("Bad height %g > %g for dot (%g, %g)\n", wantedDot.getHeight() * size_precision - epsilon, getHeight(),
1261  cog.get_u(), cog.get_v());
1262 #endif
1263  return false;
1264  }
1265 
1266  if ((getHeight() < wantedDot.getHeight() / (size_precision + epsilon)) == false) {
1267  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1268 #ifdef DEBUG
1269  printf("Bad height %g > %g for dot (%g, %g)\n", getHeight(), wantedDot.getHeight() / (size_precision + epsilon),
1270  cog.get_u(), cog.get_v());
1271 #endif
1272  return false;
1273  }
1274 
1275  if ((wantedDot.getArea() * (size_precision * size_precision) - epsilon < getArea()) == false) {
1276  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1277 #ifdef DEBUG
1278  printf("Bad surface %g > %g for dot (%g, %g)\n",
1279  wantedDot.getArea() * (size_precision * size_precision) - epsilon, getArea(), cog.get_u(), cog.get_v());
1280 #endif
1281  return false;
1282  }
1283 
1284  if ((getArea() < wantedDot.getArea() / (size_precision * size_precision + epsilon)) == false) {
1285  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1286 #ifdef DEBUG
1287  printf("Bad surface %g < %g for dot (%g, %g)\n", getArea(),
1288  wantedDot.getArea() / (size_precision * size_precision + epsilon), cog.get_u(), cog.get_v());
1289 #endif
1290  return false;
1291  }
1292  }
1293  }
1294  //
1295  // Now we can proceed to more advanced (and costy) checks.
1296  // First check there is a white (>level) elipse within dot
1297  // Then check the dot is surrounded by a black ellipse.
1298  //
1299  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1300  int nb_bad_points = 0;
1301  int nb_max_bad_points = (int)(nb_point_to_test * allowedBadPointsPercentage_);
1302  double step_angle = 2 * M_PI / nb_point_to_test;
1303 
1304  // if (ellipsoidShape_precision != 0 && compute_moment) {
1305  if (std::fabs(ellipsoidShape_precision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1306  // Chaumette, Image Moments: A General and Useful Set of Features for Visual Servoing, TRO 2004, eq 15
1307 
1308  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1309  // = m11 - m10 * m01 / m00
1310  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1311  // = m20 - m10^2 / m00
1312  // mu02 = m02 - m01^2 / m00
1313  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1314  //
1315  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1316  //
1317  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1318 
1319  // we compute parameters of the estimated ellipse
1320  double tmp1 = (m01 * m01 - m10 * m10) / m00 + (m20 - m02);
1321  double tmp2 = m11 - m10 * m01 / m00;
1322  double Sqrt = sqrt(tmp1 * tmp1 + 4 * tmp2 * tmp2);
1323  double a1 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 + Sqrt));
1324  double a2 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 - Sqrt));
1325  double alpha = 0.5 * atan2(2 * (m11 * m00 - m10 * m01), ((m20 - m02) * m00 - m10 * m10 + m01 * m01));
1326 
1327  // to be able to track small dots, minorize the ellipsoid radius for the
1328  // inner test
1329  a1 -= 1.0;
1330  a2 -= 1.0;
1331 
1332  double innerCoef = ellipsoidShape_precision;
1333  unsigned int u, v;
1334  double cog_u = this->cog.get_u();
1335  double cog_v = this->cog.get_v();
1336 
1337  vpImagePoint ip;
1338  nb_bad_points = 0;
1339  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1340  u = (unsigned int)(cog_u + innerCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1341  v = (unsigned int)(cog_v + innerCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1342  if (!this->hasGoodLevel(I, u, v)) {
1343 #ifdef DEBUG
1344  printf("Inner circle pixel (%u, %u) has bad level for dot (%g, %g): "
1345  "%d not in [%u, %u]\n",
1346  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1347 #endif
1348  // return false;
1349  nb_bad_points++;
1350  }
1351  if (graphics) {
1352  for (unsigned int t = 0; t < thickness; t++) {
1353  ip.set_u(u + t);
1354  ip.set_v(v);
1356  }
1357  }
1358 #ifdef DEBUG
1360  vpDisplay::flush(I);
1361 #endif
1362  }
1363  if (nb_bad_points > nb_max_bad_points) {
1364 #ifdef DEBUG
1365  printf("Inner ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1366 #endif
1367  return false;
1368  }
1369  // to be able to track small dots, maximize the ellipsoid radius for the
1370  // inner test
1371  a1 += 2.0;
1372  a2 += 2.0;
1373 
1374  double outCoef = 2 - ellipsoidShape_precision; // 1.6;
1375  nb_bad_points = 0;
1376  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1377  u = (unsigned int)(cog_u + outCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1378  v = (unsigned int)(cog_v + outCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1379 #ifdef DEBUG
1380  // vpDisplay::displayRectangle(I, area, vpColor::yellow);
1381  vpDisplay::displayCross(I, (int)v, (int)u, 7, vpColor::purple);
1382  vpDisplay::flush(I);
1383 #endif
1384  // If outside the area, continue
1385  if ((double)u < area.getLeft() || (double)u > area.getRight() || (double)v < area.getTop() ||
1386  (double)v > area.getBottom()) {
1387  continue;
1388  }
1389  if (!this->hasReverseLevel(I, u, v)) {
1390 #ifdef DEBUG
1391  printf("Outside circle pixel (%u, %u) has bad level for dot (%g, "
1392  "%g): %d not in [%u, %u]\n",
1393  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1394 #endif
1395  nb_bad_points++;
1396  // return false;
1397  }
1398  if (graphics) {
1399  for (unsigned int t = 0; t < thickness; t++) {
1400  ip.set_u(u + t);
1401  ip.set_v(v);
1402 
1404  }
1405  }
1406  }
1407  }
1408  if (nb_bad_points > nb_max_bad_points) {
1409 #ifdef DEBUG
1410  printf("Outside ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1411 #endif
1412  return false;
1413  }
1414 
1415  return true;
1416 }
1417 
1436 bool vpDot2::hasGoodLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1437 {
1438  if (!isInArea(u, v))
1439  return false;
1440 
1441  if (I[v][u] >= gray_level_min && I[v][u] <= gray_level_max) {
1442  return true;
1443  } else {
1444  return false;
1445  }
1446 }
1447 
1460 bool vpDot2::hasReverseLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1461 {
1462 
1463  if (!isInArea(u, v))
1464  return false;
1465 
1466  if (I[v][u] < gray_level_min || I[v][u] > gray_level_max) {
1467  return true;
1468  } else {
1469  return false;
1470  }
1471 }
1472 
1481 vpDot2 *vpDot2::getInstance() { return new vpDot2(); }
1482 
1498 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const { freeman_chain = direction_list; }
1499 
1500 /******************************************************************************
1501  *
1502  * PRIVATE METHODS
1503  *
1504  ******************************************************************************/
1505 
1537 bool vpDot2::computeParameters(const vpImage<unsigned char> &I, const double &_u, const double &_v)
1538 {
1539  direction_list.clear();
1540  ip_edges_list.clear();
1541 
1542  double est_u = _u; // estimated
1543  double est_v = _v;
1544 
1545  // if u has default value, set it to the actual center value
1546  // if( est_u == -1.0 )
1547  if (std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u), 1.) * std::numeric_limits<double>::epsilon()) {
1548  est_u = this->cog.get_u();
1549  }
1550 
1551  // if v has default value, set it to the actual center value
1552  // if( est_v == -1.0 )
1553  if (std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v), 1.) * std::numeric_limits<double>::epsilon()) {
1554  est_v = this->cog.get_v();
1555  }
1556 
1557  // if the estimated position of the dot is out of the image, not need to
1558  // continue, return an error tracking
1559  if (!isInArea((unsigned int)est_u, (unsigned int)est_v)) {
1560  vpDEBUG_TRACE(3,
1561  "Initial pixel coordinates (%d, %d) for dot tracking are "
1562  "not in the area",
1563  (int)est_u, (int)est_v);
1564  return false;
1565  }
1566 
1567  bbox_u_min = (int)I.getWidth();
1568  bbox_u_max = 0;
1569  bbox_v_min = (int)I.getHeight();
1570  bbox_v_max = 0;
1571 
1572  // if the first point doesn't have the right level then there's no point to
1573  // continue.
1574  if (!hasGoodLevel(I, (unsigned int)est_u, (unsigned int)est_v)) {
1575  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates", (int)est_u, (int)est_v);
1576  return false;
1577  }
1578 
1579  // find the border
1580 
1581  if (!findFirstBorder(I, (unsigned int)est_u, (unsigned int)est_v, this->firstBorder_u, this->firstBorder_v)) {
1582 
1583  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates", (int)est_u, (int)est_v);
1584  return false;
1585  }
1586 
1587  unsigned int dir = 6;
1588 
1589  // Determine the first element of the Freeman chain
1590  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
1591  unsigned int firstDir = dir;
1592 
1593  // if we are now out of the image, return an error tracking
1594  if (!isInArea(this->firstBorder_u, this->firstBorder_v)) {
1595  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area", this->firstBorder_u,
1596  this->firstBorder_v);
1597  return false;
1598  }
1599 
1600  // store the new direction and dot border coordinates.
1601  direction_list.push_back(dir);
1602  vpImagePoint ip;
1603  ip.set_u(this->firstBorder_u);
1604  ip.set_v(this->firstBorder_v);
1605 
1606  ip_edges_list.push_back(ip);
1607 
1608  int border_u = (int)this->firstBorder_u;
1609  int border_v = (int)this->firstBorder_v;
1610  int du, dv;
1611  float dS, dMu, dMv, dMuv, dMu2, dMv2;
1612  m00 = 0.0;
1613  m10 = 0.0;
1614  m01 = 0.0;
1615  m11 = 0.0;
1616  m20 = 0.0;
1617  m02 = 0.0;
1618  // while we didn't come back to the first point, follow the border
1619  do {
1620  // if it was asked, show the border
1621  if (graphics) {
1622  for (int t = 0; t < (int)thickness; t++) {
1623  ip.set_u(border_u + t);
1624  ip.set_v(border_v);
1625 
1627  }
1628  // vpDisplay::flush(I);
1629  }
1630 #ifdef DEBUG
1631  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1632  vpDisplay::flush(I);
1633 #endif
1634  // Determine the increments for the parameters
1635  computeFreemanParameters(border_u, border_v, dir, du, dv,
1636  dS, // surface
1637  dMu, dMv, // first order moments
1638  dMuv, dMu2, dMv2); // second order moment
1639 
1640  // Update the parameters
1641  border_u += du; // Next position on the border
1642  border_v += dv;
1643  m00 += dS; // enclosed area
1644  m10 += dMu; // First order moment along v axis
1645  m01 += dMv; // First order moment along u axis
1646  if (compute_moment) {
1647  m11 += dMuv; // Second order moment
1648  m20 += dMu2; // Second order moment along v axis
1649  m02 += dMv2; // Second order moment along u axis
1650  }
1651  // if we are now out of the image, return an error tracking
1652  if (!isInArea((unsigned int)border_u, (unsigned int)border_v)) {
1653 
1654  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
1655  // Can Occur on a single pixel dot located on the top border
1656  return false;
1657  }
1658 
1659  // store the new direction and dot border coordinates.
1660 
1661  direction_list.push_back(dir);
1662 
1663  ip.set_u(border_u);
1664  ip.set_v(border_v);
1665  ip_edges_list.push_back(ip);
1666 
1667  // vpDisplay::getClick(I);
1668 
1669  // update the extreme point of the dot.
1670  if (border_v < bbox_v_min)
1671  bbox_v_min = border_v;
1672  if (border_v > bbox_v_max)
1673  bbox_v_max = border_v;
1674  if (border_u < bbox_u_min)
1675  bbox_u_min = border_u;
1676  if (border_u > bbox_u_max)
1677  bbox_u_max = border_u;
1678 
1679  // move around the tracked entity by following the border.
1680  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
1681  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)", border_u, border_v);
1682  return false;
1683  }
1684 
1685  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v,
1686  // dir);
1687 
1688  } while ((getFirstBorder_u() != (unsigned int)border_u || getFirstBorder_v() != (unsigned int)border_v ||
1689  firstDir != dir) &&
1690  isInArea((unsigned int)border_u, (unsigned int)border_v));
1691 
1692 #ifdef VP_DEBUG
1693 #if VP_DEBUG_MODE == 3
1694  vpDisplay::flush(I);
1695 #endif
1696 #endif
1697 
1698  // if the surface is one or zero , the center of gravity wasn't properly
1699  // detected. Return an error tracking.
1700  // if( m00 == 0 || m00 == 1 )
1701  if (std::fabs(m00) <= std::numeric_limits<double>::epsilon() ||
1702  std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.) * std::numeric_limits<double>::epsilon()) {
1703  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
1704  return false;
1705  } else // compute the center
1706  {
1707  // this magic formula gives the coordinates of the center of gravity
1708  double tmpCenter_u = m10 / m00;
1709  double tmpCenter_v = m01 / m00;
1710 
1711  // Updates the second order centered moments
1712  if (compute_moment) {
1713  mu11 = m11 - tmpCenter_u * m01;
1714  mu02 = m02 - tmpCenter_v * m01;
1715  mu20 = m20 - tmpCenter_u * m10;
1716  }
1717 
1718  cog.set_u(tmpCenter_u);
1719  cog.set_v(tmpCenter_v);
1720  }
1721 
1722  width = bbox_u_max - bbox_u_min + 1;
1723  height = bbox_v_max - bbox_v_min + 1;
1724  surface = m00;
1725 
1726  computeMeanGrayLevel(I);
1727  return true;
1728 }
1729 
1745 bool vpDot2::findFirstBorder(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1746  unsigned int &border_u, unsigned int &border_v)
1747 {
1748  // find the border
1749 
1750  // NOTE:
1751  // from here we use int and not double. This is because we don't have
1752  // rounding problems and it's actually more a trouble than smth else to
1753  // work with double when navigating around the dot.
1754  border_u = u;
1755  border_v = v;
1756  double epsilon = 0.001;
1757 
1758 #ifdef DEBUG
1759  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
1760 #endif
1761  while (hasGoodLevel(I, border_u + 1, border_v) && border_u < area.getRight() /*I.getWidth()*/) {
1762  // if the width of this dot was initialised and we already crossed the dot
1763  // on more than the max possible width, no need to continue, return an
1764  // error tracking
1765  if (getWidth() > 0 && (border_u - u) > getWidth() / (getMaxSizeSearchDistancePrecision() + epsilon)) {
1766  vpDEBUG_TRACE(3,
1767  "The found dot (%d, %d, %d) has a greater width than the "
1768  "required one",
1769  u, v, border_u);
1770  return false;
1771  }
1772 #ifdef DEBUG
1773  vpDisplay::displayPoint(I, (int)border_v, (int)border_u + 1, vpColor::green);
1774  vpDisplay::flush(I);
1775 #endif
1776 
1777  border_u++;
1778  }
1779  return true;
1780 }
1781 
1800 bool vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1801  unsigned int &element)
1802 {
1803 
1804  if (hasGoodLevel(I, u, v)) {
1805  unsigned int _u = u;
1806  unsigned int _v = v;
1807  // get the point on the right of the point passed in
1808  updateFreemanPosition(_u, _v, (element + 2) % 8);
1809  if (hasGoodLevel(I, _u, _v)) {
1810  element = (element + 2) % 8; // turn right
1811  } else {
1812  unsigned int _u1 = u;
1813  unsigned int _v1 = v;
1814  updateFreemanPosition(_u1, _v1, (element + 1) % 8);
1815 
1816  if (hasGoodLevel(I, _u1, _v1)) {
1817  element = (element + 1) % 8; // turn diag right
1818  } else {
1819  unsigned int _u2 = u;
1820  unsigned int _v2 = v;
1821  updateFreemanPosition(_u2, _v2, element); // same direction
1822 
1823  if (hasGoodLevel(I, _u2, _v2)) {
1824  // element = element; // keep same dir
1825  } else {
1826  unsigned int _u3 = u;
1827  unsigned int _v3 = v;
1828  updateFreemanPosition(_u3, _v3, (element + 7) % 8); // diag left
1829 
1830  if (hasGoodLevel(I, _u3, _v3)) {
1831  element = (element + 7) % 8; // turn diag left
1832  } else {
1833  unsigned int _u4 = u;
1834  unsigned int _v4 = v;
1835  updateFreemanPosition(_u4, _v4, (element + 6) % 8); // left
1836 
1837  if (hasGoodLevel(I, _u4, _v4)) {
1838  element = (element + 6) % 8; // turn left
1839  } else {
1840  unsigned int _u5 = u;
1841  unsigned int _v5 = v;
1842  updateFreemanPosition(_u5, _v5, (element + 5) % 8); // left
1843 
1844  if (hasGoodLevel(I, _u5, _v5)) {
1845  element = (element + 5) % 8; // turn diag down
1846  } else {
1847  unsigned int _u6 = u;
1848  unsigned int _v6 = v;
1849  updateFreemanPosition(_u6, _v6, (element + 4) % 8); // left
1850 
1851  if (hasGoodLevel(I, _u6, _v6)) {
1852  element = (element + 4) % 8; // turn down
1853  } else {
1854  unsigned int _u7 = u;
1855  unsigned int _v7 = v;
1856  updateFreemanPosition(_u7, _v7, (element + 3) % 8); // diag
1857 
1858  if (hasGoodLevel(I, _u7, _v7)) {
1859  element = (element + 3) % 8; // turn diag right down
1860  } else {
1861  // No neighbor with a good level
1862  //
1863  return false;
1864  }
1865  }
1866  }
1867  }
1868  }
1869  }
1870  }
1871  }
1872  }
1873 
1874  else {
1875  return false;
1876  }
1877 
1878  return true;
1879 }
1880 
1912 void vpDot2::computeFreemanParameters(const int &u_p, const int &v_p, unsigned int &element, int &du, int &dv,
1913  float &dS, float &dMu, float &dMv, float &dMuv, float &dMu2, float &dMv2)
1914 {
1915  du = 0;
1916  dv = 0;
1917  dMuv = 0;
1918  dMu2 = 0;
1919  dMv2 = 0;
1920 
1921  /*
1922  3 2 1
1923  \ | /
1924  \|/
1925  4 ------- 0
1926  /|\
1927  / | \
1928  5 6 7
1929  */
1930  switch (element) {
1931  case 0: // go right
1932  du = 1;
1933  dS = (float)v_p;
1934  dMu = 0.0;
1935  dMv = (float)(0.5 * v_p * v_p);
1936  if (compute_moment) {
1937  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
1938  dMu2 = 0;
1939  dMv2 = (float)(1.0 / 3. * v_p * v_p * v_p);
1940  }
1941  break;
1942 
1943  case 1: // go right top
1944  du = 1;
1945  dv = 1;
1946  dS = (float)(v_p + 0.5);
1947  dMu = -(float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
1948  dMv = (float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
1949  if (compute_moment) {
1950  float half_u_p = (float)(0.5 * u_p);
1951  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) + v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
1952  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1. / 12.0);
1953  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1. / 12.0);
1954  }
1955  break;
1956 
1957  case 2: // go top
1958  dv = 1;
1959  dS = 0.0;
1960  dMu = (float)(-0.5 * u_p * u_p);
1961  dMv = 0.0;
1962  if (compute_moment) {
1963  dMuv = 0;
1964  dMu2 = (float)(-1.0 / 3. * u_p * u_p * u_p);
1965  dMv2 = 0;
1966  }
1967  break;
1968 
1969  case 3:
1970  du = -1;
1971  dv = 1;
1972  dS = (float)(-v_p - 0.5);
1973  dMu = -(float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
1974  dMv = -(float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
1975  if (compute_moment) {
1976  float half_u_p = (float)(0.5 * u_p);
1977  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) + v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
1978  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
1979  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1. / 12.0);
1980  }
1981  break;
1982 
1983  case 4:
1984  du = -1;
1985  dS = (float)(-v_p);
1986  dMv = (float)(-0.5 * v_p * v_p);
1987  dMu = 0.0;
1988  if (compute_moment) {
1989  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
1990  dMu2 = 0;
1991  dMv2 = (float)(-1.0 / 3. * v_p * v_p * v_p);
1992  }
1993  break;
1994 
1995  case 5:
1996  du = -1;
1997  dv = -1;
1998  dS = (float)(-v_p + 0.5);
1999  dMu = (float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2000  dMv = (float)(-(0.5 * v_p * (v_p - 1) + 1.0 / 6.0));
2001  if (compute_moment) {
2002  float half_u_p = (float)(0.5 * u_p);
2003  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) - v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2004  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2005  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2006  }
2007  break;
2008 
2009  case 6:
2010  dv = -1;
2011  dS = 0.0;
2012  dMu = (float)(0.5 * u_p * u_p);
2013  dMv = 0.0;
2014  if (compute_moment) {
2015  dMuv = 0;
2016  dMu2 = (float)(1.0 / 3. * u_p * u_p * u_p);
2017  dMv2 = 0;
2018  }
2019  break;
2020 
2021  case 7:
2022  du = 1;
2023  dv = -1;
2024  dS = (float)(v_p - 0.5);
2025  dMu = (float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
2026  dMv = (float)(0.5 * v_p * (v_p - 1) + 1.0 / 6.0);
2027  if (compute_moment) {
2028  float half_u_p = (float)(0.5 * u_p);
2029  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) - v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
2030  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1. / 12.0);
2031  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2032  }
2033  break;
2034  }
2035 }
2036 
2050 void vpDot2::updateFreemanPosition(unsigned int &u, unsigned int &v, const unsigned int &dir)
2051 {
2052  switch (dir) {
2053  case 0:
2054  u += 1;
2055  break;
2056  case 1:
2057  u += 1;
2058  v += 1;
2059  break;
2060  case 2:
2061  v += 1;
2062  break;
2063  case 3:
2064  u -= 1;
2065  v += 1;
2066  break;
2067  case 4:
2068  u -= 1;
2069  break;
2070  case 5:
2071  u -= 1;
2072  v -= 1;
2073  break;
2074  case 6:
2075  v -= 1;
2076  break;
2077  case 7:
2078  u += 1;
2079  v -= 1;
2080  break;
2081  }
2082 }
2083 
2095 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const { return isInImage(I, cog); }
2096 
2108 bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
2109 {
2110  unsigned int h = I.getHeight();
2111  unsigned int w = I.getWidth();
2112  double u = ip.get_u();
2113  double v = ip.get_v();
2114 
2115  if (u < 0 || u >= w)
2116  return false;
2117  if (v < 0 || v >= h)
2118  return false;
2119  return true;
2120 }
2121 
2133 bool vpDot2::isInArea(const unsigned int &u, const unsigned int &v) const
2134 {
2135  unsigned int area_u_min = (unsigned int)area.getLeft();
2136  unsigned int area_u_max = (unsigned int)area.getRight();
2137  unsigned int area_v_min = (unsigned int)area.getTop();
2138  unsigned int area_v_max = (unsigned int)area.getBottom();
2139 
2140  if (u < area_u_min || u > area_u_max)
2141  return false;
2142  if (v < area_v_min || v > area_v_max)
2143  return false;
2144  return true;
2145 }
2146 
2158 void vpDot2::getGridSize(unsigned int &gridWidth, unsigned int &gridHeight)
2159 {
2160  // first get the research grid width and height Note that
2161  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2162  // contained in the dot. We gent this here if the dot is a perfect disc.
2163  // More accurate criterium to define the grid should be implemented if
2164  // necessary
2165  gridWidth = (unsigned int)(getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2166  gridHeight = (unsigned int)(getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2167 
2168  if (gridWidth == 0)
2169  gridWidth = 1;
2170  if (gridHeight == 0)
2171  gridHeight = 1;
2172 }
2173 
2186 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char> &I)
2187 {
2188  int cog_u = (int)cog.get_u();
2189  int cog_v = (int)cog.get_v();
2190 
2191  unsigned int sum_value = 0;
2192  unsigned int nb_pixels = 0;
2193 
2194  for (unsigned int i = (unsigned int)this->bbox_u_min; i <= (unsigned int)this->bbox_u_max; i++) {
2195  unsigned int pixel_gray = (unsigned int)I[(unsigned int)cog_v][i];
2196  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2197  sum_value += pixel_gray;
2198  nb_pixels++;
2199  }
2200  }
2201  for (unsigned int i = (unsigned int)this->bbox_v_min; i <= (unsigned int)this->bbox_v_max; i++) {
2202  unsigned char pixel_gray = I[i][(unsigned int)cog_u];
2203  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2204  sum_value += pixel_gray;
2205  nb_pixels++;
2206  }
2207  }
2208  if (nb_pixels < 10) { // could be good to choose the min nb points from area of dot
2209  // add diagonals points to have enough point
2210  int imin, imax;
2211  if ((cog_u - bbox_u_min) > (cog_v - bbox_v_min)) {
2212  imin = cog_v - bbox_v_min;
2213  } else {
2214  imin = cog_u - bbox_u_min;
2215  }
2216  if ((bbox_u_max - cog_u) > (bbox_v_max - cog_v)) {
2217  imax = bbox_v_max - cog_v;
2218  } else {
2219  imax = bbox_u_max - cog_u;
2220  }
2221  for (int i = -imin; i <= imax; i++) {
2222  unsigned int pixel_gray = (unsigned int)I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2223  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2224  sum_value += pixel_gray;
2225  nb_pixels++;
2226  }
2227  }
2228 
2229  if ((cog_u - bbox_u_min) > (bbox_v_max - cog_v)) {
2230  imin = bbox_v_max - cog_v;
2231  } else {
2232  imin = cog_u - bbox_u_min;
2233  }
2234  if ((bbox_u_max - cog_u) > (cog_v - bbox_v_min)) {
2235  imax = cog_v - bbox_v_min;
2236  } else {
2237  imax = bbox_u_max - cog_u;
2238  }
2239 
2240  for (int i = -imin; i <= imax; i++) {
2241  unsigned char pixel_gray = I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2242  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2243  sum_value += pixel_gray;
2244  nb_pixels++;
2245  }
2246  }
2247  }
2248 
2249  if (nb_pixels == 0) {
2250  // should never happen
2251  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No point was found"));
2252  } else {
2253  mean_gray_level = sum_value / nb_pixels;
2254  }
2255 }
2256 
2275 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I,
2276  vpColor col, bool trackDot)
2277 {
2278  vpMatrix Cogs(n, 2);
2279  vpImagePoint cog;
2280  unsigned int i;
2281  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
2282  if (fromFile) {
2283  vpMatrix::loadMatrix(dotFile, Cogs);
2284  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
2285  }
2286 
2287  // test number of cogs in file
2288  if (Cogs.getRows() < n) {
2289  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
2290  fromFile = false;
2291  }
2292 
2293  // read from file and tracks the dots
2294  if (fromFile) {
2295  try {
2296  for (i = 0; i < n; ++i) {
2297  cog.set_uv(Cogs[i][0], Cogs[i][1]);
2298  dot[i].setGraphics(true);
2299  dot[i].setCog(cog);
2300  if (trackDot) {
2301  dot[i].initTracking(I, cog);
2302  dot[i].track(I);
2303  vpDisplay::displayCross(I, cog, 10, col);
2304  }
2305  }
2306  } catch (...) {
2307  std::cout << "Cannot track dots from file" << std::endl;
2308  fromFile = false;
2309  }
2310  vpDisplay::flush(I);
2311 
2312  // check that dots are far away ones from the other
2313  for (i = 0; i < n && fromFile; ++i) {
2314  double d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
2315  for (unsigned int j = 0; j < n && fromFile; ++j)
2316  if (j != i)
2317  if (dot[i].getDistance(dot[j]) < d) {
2318  fromFile = false;
2319  std::cout << "Dots from file seem incoherent" << std::endl;
2320  }
2321  }
2322  }
2323 
2324  if (!fromFile) {
2325  vpDisplay::display(I);
2326  vpDisplay::flush(I);
2327 
2328  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
2329  for (i = 0; i < n; i++) {
2330  if (trackDot) {
2331  dot[i].setGraphics(true);
2332  dot[i].initTracking(I);
2333  cog = dot[i].getCog();
2334  } else {
2335  vpDisplay::getClick(I, cog);
2336  dot[i].setCog(cog);
2337  }
2338  Cogs[i][0] = cog.get_u();
2339  Cogs[i][1] = cog.get_v();
2340  vpDisplay::displayCross(I, cog, 10, col);
2341  vpDisplay::flush(I);
2342  }
2343  }
2344 
2345  if (!fromFile && (dotFile != "")) {
2346  vpMatrix::saveMatrix(dotFile, Cogs);
2347  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
2348  }
2349 
2350  // back to non graphic mode
2351  for (i = 0; i < n; ++i)
2352  dot[i].setGraphics(false);
2353 
2354  return Cogs;
2355 }
2356 
2373 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I,
2374  std::vector<vpImagePoint> &cogs, vpImagePoint *cogStar)
2375 {
2376  unsigned int i;
2377  // tracking
2378  for (i = 0; i < n; ++i) {
2379  dot[i].track(I);
2380  cogs.push_back(dot[i].getCog());
2381  }
2382  // trajectories
2383  for (i = n; i < cogs.size(); ++i)
2384  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::green, true);
2385  // initial position
2386  for (i = 0; i < n; ++i)
2387  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::blue, true);
2388  // if exists, desired position
2389  if (cogStar != NULL)
2390  for (i = 0; i < n; ++i) {
2391  vpDisplay::displayDotLine(I, cogStar[i], dot[i].getCog(), vpColor::red);
2392  vpDisplay::displayCircle(I, cogStar[i], 4, vpColor::red, true);
2393  }
2394  vpDisplay::flush(I);
2395 }
2396 
2412  const std::list<vpImagePoint> &edges_list, vpColor color, unsigned int thickness)
2413 {
2414  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2415  std::list<vpImagePoint>::const_iterator it;
2416 
2417  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2418  vpDisplay::displayPoint(I, *it, color);
2419  }
2420 }
2421 
2436 void vpDot2::display(const vpImage<vpRGBa> &I, const vpImagePoint &cog, const std::list<vpImagePoint> &edges_list,
2437  vpColor color, unsigned int thickness)
2438 {
2439  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2440  std::list<vpImagePoint>::const_iterator it;
2441 
2442  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2443  vpDisplay::displayPoint(I, *it, color);
2444  }
2445 }
2446 
2452 VISP_EXPORT std::ostream &operator<<(std::ostream &os, vpDot2 &d) { return (os << "(" << d.getCog() << ")"); }
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition: vpArray2D.h:529
unsigned int getRows() const
Definition: vpArray2D.h:290
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:152
static const vpColor red
Definition: vpColor.h:211
static const vpColor blue
Definition: vpColor.h:217
static const vpColor purple
Definition: vpColor.h:222
static const vpColor green
Definition: vpColor.h:214
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void displayCircle(const vpImage< unsigned char > &I, const vpImageCircle &circle, const vpColor &color, bool fill=false, unsigned int thickness=1)
static void display(const vpImage< unsigned char > &I)
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void flush(const vpImage< unsigned char > &I)
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
static void displayDotLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
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)
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:124
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:217
vpDot2()
Definition: vpDot2.cpp:103
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:223
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:2373
void track(const vpImage< unsigned char > &I, bool canMakeTheWindowGrow=true)
Definition: vpDot2.cpp:441
double m02
Definition: vpDot2.h:412
double m01
Definition: vpDot2.h:388
virtual ~vpDot2()
Definition: vpDot2.cpp:197
void setGraphics(bool activate)
Definition: vpDot2.h:311
double mu11
Definition: vpDot2.h:421
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:815
vpDot2 & operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:146
void setGraphicsThickness(unsigned int t)
Definition: vpDot2.h:318
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:642
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:961
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1) const
Definition: vpDot2.cpp:211
double m20
Definition: vpDot2.h:403
double m00
Definition: vpDot2.h:372
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:348
double getArea() const
Definition: vpDot2.cpp:619
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:745
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:717
double m11
Definition: vpDot2.h:396
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:331
void getFreemanChain(std::list< unsigned int > &freeman_chain) const
Definition: vpDot2.cpp:1498
void setHeight(const double &height)
Definition: vpDot2.cpp:686
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:650
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:257
vpImagePoint getCog() const
Definition: vpDot2.h:177
double m10
Definition: vpDot2.h:380
double getSizePrecision() const
Definition: vpDot2.cpp:633
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:626
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:287
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:655
double mu02
Definition: vpDot2.h:431
void setWidth(const double &width)
Definition: vpDot2.cpp:674
double mu20
Definition: vpDot2.h:426
double getWidth() const
Definition: vpDot2.cpp:605
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:788
double getMeanGrayLevel() const
Definition: vpDot2.h:231
void setArea(const double &area)
Definition: vpDot2.cpp:698
void setComputeMoments(bool activate)
Definition: vpDot2.h:273
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:252
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:2275
double getHeight() const
Definition: vpDot2.cpp:612
error that can be emitted by ViSP classes.
Definition: vpException.h:59
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_j() const
Definition: vpImagePoint.h:125
double get_u() const
Definition: vpImagePoint.h:136
void set_u(double u)
Definition: vpImagePoint.h:328
void set_uv(double u, double v)
Definition: vpImagePoint.h:350
void set_v(double v)
Definition: vpImagePoint.h:339
double get_i() const
Definition: vpImagePoint.h:114
double get_v() const
Definition: vpImagePoint.h:147
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getHeight() const
Definition: vpImage.h:184
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:835
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:172
static double sqr(double x)
Definition: vpMath.h:124
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:152
static bool loadMatrix(const std::string &filename, vpArray2D< double > &M, bool binary=false, char *header=NULL)
Definition: vpMatrix.h:763
static bool saveMatrix(const std::string &filename, const vpArray2D< double > &M, bool binary=false, const char *header="")
Definition: vpMatrix.h:911
Defines a rectangle in the plane.
Definition: vpRect.h:76
double getLeft() const
Definition: vpRect.h:170
void setRect(double l, double t, double w, double h)
Definition: vpRect.h:330
double getRight() const
Definition: vpRect.h:176
double getBottom() const
Definition: vpRect.h:94
double getTop() const
Definition: vpRect.h:189
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:60
Error that can be emitted by the vpTracker class and its derivatives.
@ featureLostError
Tracker lost feature.
@ notEnoughPointError
Not enough point to track.
#define vpTRACE
Definition: vpDebug.h:411
#define vpDEBUG_TRACE
Definition: vpDebug.h:482