Visual Servoing Platform  version 3.5.1 under development (2022-12-06)
vpDot2.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Fabien Spindler
36  * Anthony Saunier
37  *
38  *****************************************************************************/
39 
45 //#define DEBUG
46 
47 #include <visp3/core/vpDisplay.h>
48 
49 // exception handling
50 #include <visp3/core/vpIoTools.h>
51 #include <visp3/core/vpMath.h>
52 #include <visp3/core/vpTrackingException.h>
53 
54 #include <cmath> // std::fabs
55 #include <iostream>
56 #include <limits> // numeric_limits
57 #include <math.h>
58 #include <visp3/blob/vpDot2.h>
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.), mu11(0.), mu20(0.), mu02(0.), cog(), width(0), height(0),
106  surface(0), gray_level_min(128), gray_level_max(255), mean_gray_level(0), grayLevelPrecision(0.8), gamma(1.5),
107  sizePrecision(0.65), ellipsoidShapePrecision(0.65), maxSizeSearchDistancePrecision(0.65),
108  allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(), compute_moment(false), graphics(false),
109  thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0), firstBorder_u(0), firstBorder_v()
110 {
111 }
112 
122  : m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), cog(ip), width(0), height(0),
123  surface(0), gray_level_min(128), gray_level_max(255), mean_gray_level(0), grayLevelPrecision(0.8), gamma(1.5),
124  sizePrecision(0.65), ellipsoidShapePrecision(0.65), maxSizeSearchDistancePrecision(0.65),
125  allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(), compute_moment(false), graphics(false),
126  thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0), firstBorder_u(0), firstBorder_v()
127 {
128 }
129 
133 vpDot2::vpDot2(const vpDot2 &twinDot)
134  : vpTracker(twinDot), m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), cog(),
135  width(0), height(0), surface(0), gray_level_min(128), gray_level_max(255), mean_gray_level(0),
136  grayLevelPrecision(0.8), gamma(1.5), sizePrecision(0.65), ellipsoidShapePrecision(0.65),
137  maxSizeSearchDistancePrecision(0.65), allowedBadPointsPercentage_(0.), area(), direction_list(), ip_edges_list(),
138  compute_moment(false), graphics(false), thickness(1), bbox_u_min(0), bbox_u_max(0), bbox_v_min(0), bbox_v_max(0),
139  firstBorder_u(0), firstBorder_v()
140 {
141  *this = twinDot;
142 }
143 
148 {
149  cog = twinDot.cog;
150 
151  width = twinDot.width;
152  height = twinDot.height;
153  surface = twinDot.surface;
154  gray_level_min = twinDot.gray_level_min;
155  gray_level_max = twinDot.gray_level_max;
156  mean_gray_level = twinDot.mean_gray_level;
157  grayLevelPrecision = twinDot.grayLevelPrecision;
158  gamma = twinDot.gamma;
159  ;
160  sizePrecision = twinDot.sizePrecision;
161  ellipsoidShapePrecision = twinDot.ellipsoidShapePrecision;
162  maxSizeSearchDistancePrecision = twinDot.maxSizeSearchDistancePrecision;
163  allowedBadPointsPercentage_ = twinDot.allowedBadPointsPercentage_;
164  area = twinDot.area;
165 
166  direction_list = twinDot.direction_list;
167  ip_edges_list = twinDot.ip_edges_list;
168 
169  compute_moment = twinDot.compute_moment;
170  graphics = twinDot.graphics;
171  thickness = twinDot.thickness;
172 
173  bbox_u_min = twinDot.bbox_u_min;
174  bbox_u_max = twinDot.bbox_u_max;
175  bbox_v_min = twinDot.bbox_v_min;
176  bbox_v_max = twinDot.bbox_v_max;
177 
178  firstBorder_u = twinDot.firstBorder_u;
179  firstBorder_v = twinDot.firstBorder_v;
180 
181  m00 = twinDot.m00;
182  m01 = twinDot.m01;
183  m11 = twinDot.m11;
184  m10 = twinDot.m10;
185  m02 = twinDot.m02;
186  m20 = twinDot.m20;
187 
188  mu11 = twinDot.mu11;
189  mu20 = twinDot.mu20;
190  mu02 = twinDot.mu02;
191 
192  return (*this);
193 }
194 
199 
200 /******************************************************************************
201  *
202  * PUBLIC METHODS
203  *****************************************************************************/
204 
212 void vpDot2::display(const vpImage<unsigned char> &I, vpColor color, unsigned int t) const
213 {
214  vpDisplay::displayCross(I, cog, 3 * t + 8, color, t);
215  std::list<vpImagePoint>::const_iterator it;
216 
217  for (it = ip_edges_list.begin(); it != ip_edges_list.end(); ++it) {
218  vpDisplay::displayPoint(I, *it, color);
219  }
220 }
221 
253 void vpDot2::initTracking(const vpImage<unsigned char> &I, unsigned int size)
254 {
255  while (vpDisplay::getClick(I, cog) != true) {
256  }
257 
258  unsigned int i = (unsigned int)cog.get_i();
259  unsigned int j = (unsigned int)cog.get_j();
260 
261  double Ip = pow((double)I[i][j] / 255, 1 / gamma);
262 
263  if (Ip - (1 - grayLevelPrecision) < 0) {
264  gray_level_min = 0;
265  } else {
266  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
267  if (gray_level_min > 255)
268  gray_level_min = 255;
269  }
270  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
271  if (gray_level_max > 255)
272  gray_level_max = 255;
273 
274  setWidth(size);
275  setHeight(size);
276 
277  try {
278  track(I);
279  } catch (const vpException &e) {
280  // vpERROR_TRACE("Error caught") ;
281  throw(e);
282  }
283 }
284 
312 void vpDot2::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip, unsigned int size)
313 {
314  cog = ip;
315 
316  unsigned int i = (unsigned int)cog.get_i();
317  unsigned int j = (unsigned int)cog.get_j();
318 
319  double Ip = pow((double)I[i][j] / 255, 1 / gamma);
320 
321  if (Ip - (1 - grayLevelPrecision) < 0) {
322  gray_level_min = 0;
323  } else {
324  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
325  if (gray_level_min > 255)
326  gray_level_min = 255;
327  }
328  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
329  if (gray_level_max > 255)
330  gray_level_max = 255;
331 
332  setWidth(size);
333  setHeight(size);
334 
335  try {
336  track(I);
337  } catch (const vpException &e) {
338  // vpERROR_TRACE("Error caught") ;
339  throw(e);
340  }
341 }
342 
382 void vpDot2::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip, unsigned int gray_lvl_min,
383  unsigned int gray_lvl_max, unsigned int size)
384 {
385  cog = ip;
386 
387  this->gray_level_min = gray_lvl_min;
388  this->gray_level_max = gray_lvl_max;
389 
390  setWidth(size);
391  setHeight(size);
392 
393  try {
394  track(I);
395  } catch (const vpException &e) {
396  // vpERROR_TRACE("Error caught") ;
397  throw(e);
398  }
399 }
400 
442 void vpDot2::track(const vpImage<unsigned char> &I, bool canMakeTheWindowGrow)
443 {
444  m00 = m11 = m02 = m20 = m10 = m01 = 0;
445 
446  // First, we will estimate the position of the tracked point
447 
448  // Set the search area to the entire image
449  setArea(I);
450 
451  // create a copy of the dot to search
452  // This copy can be saw as the previous dot used to check if the current one
453  // found with computeParameters() is similar to the previous one (see
454  // isValid() function). If the found dot is not similar (or valid), we use
455  // this copy to set the current found dot to the previous one (see below).
456  vpDot2 wantedDot(*this);
457 
458  // vpDEBUG_TRACE(0, "Previous dot: ");
459  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
460  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
461  bool found = computeParameters(I, cog.get_u(), cog.get_v());
462 
463  if (found) {
464  // test if the found dot is valid (ie similar to the previous one)
465  found = isValid(I, wantedDot);
466  if (!found) {
467  *this = wantedDot;
468  // std::cout << "The found dot is not valid" << std::endl;
469  }
470  }
471 
472  if (!found) {
473  // vpDEBUG_TRACE(0, "Search the dot in a biggest window around the
474  // last position"); vpDEBUG_TRACE(0, "Bad computed dot: ");
475  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
476  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
477 
478  // if estimation was wrong (get an error tracking), look for the dot
479  // closest from the estimation,
480  // i.e. search for dots in an a region of interest around the this dot and
481  // get the first element in the area.
482 
483  // first get the size of the search window from the dot size
484  double searchWindowWidth = 0.0, searchWindowHeight = 0.0;
485  // if( getWidth() == 0 || getHeight() == 0 )
486  if (std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() ||
487  std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon()) {
488  searchWindowWidth = 80.;
489  searchWindowHeight = 80.;
490  } else if (canMakeTheWindowGrow) {
491  searchWindowWidth = getWidth() * 5;
492  searchWindowHeight = getHeight() * 5;
493  } else {
494  searchWindowWidth = getWidth();
495  searchWindowHeight = getHeight();
496  }
497 
498  std::list<vpDot2> candidates;
499  searchDotsInArea(I, (int)(this->cog.get_u() - searchWindowWidth / 2.0),
500  (int)(this->cog.get_v() - searchWindowHeight / 2.0), (unsigned int)searchWindowWidth,
501  (unsigned int)searchWindowHeight, candidates);
502 
503  // if the vector is empty, that mean we didn't find any candidate
504  // in the area, return an error tracking.
505  if (candidates.empty()) {
506  // vpERROR_TRACE("No dot was found") ;
508  }
509 
510  // otherwise we've got our dot, update this dot's parameters
511  vpDot2 movingDot = candidates.front();
512 
513  setCog(movingDot.getCog());
514  setArea(movingDot.getArea());
515  setWidth(movingDot.getWidth());
516  setHeight(movingDot.getHeight());
517 
518  // Update the moments
519  m00 = movingDot.m00;
520  m01 = movingDot.m01;
521  m10 = movingDot.m10;
522  m11 = movingDot.m11;
523  m20 = movingDot.m20;
524  m02 = movingDot.m02;
525 
526  // Update the bounding box
527  bbox_u_min = movingDot.bbox_u_min;
528  bbox_u_max = movingDot.bbox_u_max;
529  bbox_v_min = movingDot.bbox_v_min;
530  bbox_v_max = movingDot.bbox_v_max;
531  }
532  // else {
533  // // test if the found dot is valid,
534  // if( ! isValid( I, wantedDot ) ) {
535  // *this = wantedDot;
536  // vpERROR_TRACE("The found dot is invalid:",
537  // "- could be a problem of size (width or height) or "
538  // " surface (number of pixels) which differ too much "
539  // " to the previous one "
540  // "- or a problem of the shape which is not ellipsoid if "
541  // " use setEllipsoidShapePrecision(double
542  // ellipsoidShapePrecision) "
543  // " which is the default case. "
544  // " To track a non ellipsoid shape use
545  // setEllipsoidShapePrecision(0)") ;
546  // throw(vpTrackingException(vpTrackingException::featureLostError,
547  // "The found dot is invalid")) ;
548  // }
549  // }
550 
551  // if this dot is partially out of the image, return an error tracking.
552  if (!isInImage(I)) {
553  // vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
555  "The center of gravity of the dot is not in the image"));
556  }
557 
558  // Get dots center of gravity
559  // unsigned int u = (unsigned int) this->cog.get_u();
560  // unsigned int v = (unsigned int) this->cog.get_v();
561  // Updates the min and max gray levels for the next iteration
562  // double Ip = pow((double)I[v][u]/255,1/gamma);
563  double Ip = pow(getMeanGrayLevel() / 255, 1 / gamma);
564  // printf("current value of gray level center : %i\n", I[v][u]);
565 
566  // getMeanGrayLevel(I);
567  if (Ip - (1 - grayLevelPrecision) < 0) {
568  gray_level_min = 0;
569  } else {
570  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
571  if (gray_level_min > 255)
572  gray_level_min = 255;
573  }
574  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
575  if (gray_level_max > 255)
576  gray_level_max = 255;
577 
578  // printf("%i %i \n",gray_level_max,gray_level_min);
579  if (graphics) {
580  // display a red cross at the center of gravity's location in the image.
581 
582  vpDisplay::displayCross(I, this->cog, 3 * thickness + 8, vpColor::red, thickness);
583  // vpDisplay::flush(I);
584  }
585 }
586 
609 void vpDot2::track(const vpImage<unsigned char> &I, vpImagePoint &ip, bool canMakeTheWindowGrow)
610 {
611  track(I, canMakeTheWindowGrow);
612 
613  ip = this->cog;
614 }
615 
618 
624 double vpDot2::getWidth() const { return width; }
625 
631 double vpDot2::getHeight() const { return height; }
632 
638 double vpDot2::getArea() const { return fabs(surface); }
639 
645 double vpDot2::getGrayLevelPrecision() const { return grayLevelPrecision; }
646 
652 double vpDot2::getSizePrecision() const { return sizePrecision; }
653 
661 double vpDot2::getEllipsoidShapePrecision() const { return ellipsoidShapePrecision; }
662 
669 double vpDot2::getMaxSizeSearchDistancePrecision() const { return maxSizeSearchDistancePrecision; }
670 
674 double vpDot2::getDistance(const vpDot2 &distantDot) const
675 {
676  vpImagePoint cogDistantDot = distantDot.getCog();
677  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
678  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
679  return sqrt(diff_u * diff_u + diff_v * diff_v);
680 }
681 
683 
693 void vpDot2::setWidth(const double &w) { this->width = w; }
694 
705 void vpDot2::setHeight(const double &h) { this->height = h; }
706 
717 void vpDot2::setArea(const double &a) { this->surface = a; }
718 
736 void vpDot2::setGrayLevelPrecision(const double &precision)
737 {
738  double epsilon = 0.05;
739  if (grayLevelPrecision < epsilon) {
740  this->grayLevelPrecision = epsilon;
741  } else if (grayLevelPrecision > 1) {
742  this->grayLevelPrecision = 1.0;
743  } else {
744  this->grayLevelPrecision = precision;
745  }
746 }
764 void vpDot2::setSizePrecision(const double &precision)
765 {
766  if (sizePrecision < 0) {
767  this->sizePrecision = 0;
768  } else if (sizePrecision > 1) {
769  this->sizePrecision = 1.0;
770  } else {
771  this->sizePrecision = precision;
772  }
773 }
774 
807 void vpDot2::setEllipsoidShapePrecision(const double &precision)
808 {
809 
810  if (ellipsoidShapePrecision < 0) {
811  this->ellipsoidShapePrecision = 0;
812  } else if (ellipsoidShapePrecision > 1) {
813  this->ellipsoidShapePrecision = 1.0;
814  } else {
815  this->ellipsoidShapePrecision = precision;
816  }
817 }
818 
834 void vpDot2::setMaxSizeSearchDistancePrecision(const double &precision)
835 {
836  double epsilon = 0.05;
837  if (maxSizeSearchDistancePrecision < epsilon) {
838  this->maxSizeSearchDistancePrecision = epsilon;
839  } else if (maxSizeSearchDistancePrecision > 1) {
840  this->maxSizeSearchDistancePrecision = 1.0;
841  } else {
842  this->maxSizeSearchDistancePrecision = precision;
843  }
844 }
845 
854 void vpDot2::setArea(const vpImage<unsigned char> &I) { setArea(I, 0, 0, I.getWidth(), I.getHeight()); }
855 
868 void vpDot2::setArea(const vpImage<unsigned char> &I, int u, int v, unsigned int w, unsigned int h)
869 {
870  unsigned int image_w = I.getWidth();
871  unsigned int image_h = I.getHeight();
872 
873  // Bounds the area to the image
874  if (u < 0)
875  u = 0;
876  else if (u >= (int)image_w)
877  u = (int)image_w - 1;
878  if (v < 0)
879  v = 0;
880  else if (v >= (int)image_h)
881  v = (int)image_h - 1;
882 
883  if (((unsigned int)u + w) > image_w)
884  w = image_w - (unsigned int)u - 1;
885  if (((unsigned int)v + h) > image_h)
886  h = image_h - (unsigned int)v - 1;
887 
888  area.setRect(u, v, w, h);
889 }
890 
898 void vpDot2::setArea(const vpRect &a) { area = a; }
899 
901 
953 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, std::list<vpDot2> &niceDots)
954 {
955  searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
956 }
957 
980 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, int area_u, int area_v, unsigned int area_w,
981  unsigned int area_h, std::list<vpDot2> &niceDots)
982 
983 {
984  // clear the list of nice dots
985  niceDots.clear();
986 
987  // Fit the input area in the image; we keep only the common part between
988  // this area and the image.
989  setArea(I, area_u, area_v, area_w, area_h);
990 
991  // compute the size of the search grid
992  unsigned int gridWidth;
993  unsigned int gridHeight;
994  getGridSize(gridWidth, gridHeight);
995 
996  if (graphics) {
997  // Display the area were the dot is search
998  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
999  // vpDisplay::flush(I);
1000  }
1001 
1002 #ifdef DEBUG
1004  vpDisplay::flush(I);
1005 #endif
1006  // start the search loop; for all points of the search grid,
1007  // test if the pixel belongs to a valid dot.
1008  // if it is so eventually add it to the vector of valid dots.
1009  std::list<vpDot2> badDotsVector;
1010  std::list<vpDot2>::iterator itnice;
1011  std::list<vpDot2>::iterator itbad;
1012 
1013  vpDot2 *dotToTest = NULL;
1014  vpDot2 tmpDot;
1015 
1016  unsigned int area_u_min = (unsigned int)area.getLeft();
1017  unsigned int area_u_max = (unsigned int)area.getRight();
1018  unsigned int area_v_min = (unsigned int)area.getTop();
1019  unsigned int area_v_max = (unsigned int)area.getBottom();
1020 
1021  unsigned int u, v;
1022  vpImagePoint cogTmpDot;
1023 
1024  for (v = area_v_min; v < area_v_max; v = v + gridHeight) {
1025  for (u = area_u_min; u < area_u_max; u = u + gridWidth) {
1026  // if the pixel we're in doesn't have the right color (outside the
1027  // graylevel interval), no need to check further, just get to the
1028  // next grid intersection.
1029  if (!hasGoodLevel(I, u, v))
1030  continue;
1031 
1032  // Test if an other germ is inside the bounding box of a dot previously
1033  // detected
1034  bool good_germ = true;
1035 
1036  itnice = niceDots.begin();
1037  while (itnice != niceDots.end() && good_germ == true) {
1038  tmpDot = *itnice;
1039 
1040  cogTmpDot = tmpDot.getCog();
1041  double u0 = cogTmpDot.get_u();
1042  double v0 = cogTmpDot.get_v();
1043  double half_w = tmpDot.getWidth() / 2.;
1044  double half_h = tmpDot.getHeight() / 2.;
1045 
1046  if (u >= (u0 - half_w) && u <= (u0 + half_w) && v >= (v0 - half_h) && v <= (v0 + half_h)) {
1047  // Germ is in a previously detected dot
1048  good_germ = false;
1049  }
1050  ++itnice;
1051  }
1052 
1053  if (!good_germ)
1054  continue;
1055 
1056  // Compute the right border position for this possible germ
1057  unsigned int border_u;
1058  unsigned int border_v;
1059  if (findFirstBorder(I, u, v, border_u, border_v) == false) {
1060  // germ is not good.
1061  // Jump all the pixels between v,u and v,
1062  // dotToTest->getFirstBorder_u()
1063  u = border_u;
1064  v = border_v;
1065  continue;
1066  }
1067 
1068  itbad = badDotsVector.begin();
1069 #define vpBAD_DOT_VALUE (*itbad)
1070  vpImagePoint cogBadDot;
1071 
1072  while (itbad != badDotsVector.end() && good_germ == true) {
1073  if ((double)u >= vpBAD_DOT_VALUE.bbox_u_min && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1074  (double)v >= vpBAD_DOT_VALUE.bbox_v_min && (double)v <= vpBAD_DOT_VALUE.bbox_v_max) {
1075  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1076  while (it_edges != ip_edges_list.end() && good_germ == true) {
1077  // Test if the germ belong to a previously detected dot:
1078  // - from the germ go right to the border and compare this
1079  // position to the list of pixels of previously detected dots
1080  cogBadDot = *it_edges;
1081  // if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1082  if ((std::fabs(border_u - cogBadDot.get_u()) <=
1083  vpMath::maximum(std::fabs((double)border_u), std::fabs(cogBadDot.get_u())) *
1084  std::numeric_limits<double>::epsilon()) &&
1085  (std::fabs(v - cogBadDot.get_v()) <=
1086  vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v())) *
1087  std::numeric_limits<double>::epsilon())) {
1088  good_germ = false;
1089  }
1090  ++it_edges;
1091  }
1092  }
1093  ++itbad;
1094  }
1095 #undef vpBAD_DOT_VALUE
1096 
1097  if (!good_germ) {
1098  // Jump all the pixels between v,u and v,
1099  // dotToTest->getFirstBorder_u()
1100  u = border_u;
1101  v = border_v;
1102  continue;
1103  }
1104 
1105  vpTRACE(4, "Try germ (%d, %d)", u, v);
1106 
1107  vpImagePoint germ;
1108  germ.set_u(u);
1109  germ.set_v(v);
1110 
1111  // otherwise estimate the width, height and surface of the dot we
1112  // created, and test it.
1113  if (dotToTest != NULL)
1114  delete dotToTest;
1115  dotToTest = getInstance();
1116  dotToTest->setCog(germ);
1117  dotToTest->setGrayLevelMin(getGrayLevelMin());
1118  dotToTest->setGrayLevelMax(getGrayLevelMax());
1120  dotToTest->setSizePrecision(getSizePrecision());
1121  dotToTest->setGraphics(graphics);
1122  dotToTest->setGraphicsThickness(thickness);
1123  dotToTest->setComputeMoments(true);
1124  dotToTest->setArea(area);
1125  dotToTest->setEllipsoidShapePrecision(ellipsoidShapePrecision);
1126  dotToTest->setEllipsoidBadPointsPercentage(allowedBadPointsPercentage_);
1127 
1128  // first compute the parameters of the dot.
1129  // if for some reasons this caused an error tracking
1130  // (dot partially out of the image...), check the next intersection
1131  if (dotToTest->computeParameters(I) == false) {
1132  // Jump all the pixels between v,u and v,
1133  // dotToTest->getFirstBorder_u()
1134  u = border_u;
1135  v = border_v;
1136  continue;
1137  }
1138  // if the dot to test is valid,
1139  if (dotToTest->isValid(I, *this)) {
1140  vpImagePoint cogDotToTest = dotToTest->getCog();
1141  // Compute the distance to the center. The center used here is not the
1142  // area center available by area.getCenter(area_center_u,
1143  // area_center_v) but the center of the input area which may be
1144  // partially outside the image.
1145 
1146  double area_center_u = area_u + area_w / 2.0 - 0.5;
1147  double area_center_v = area_v + area_h / 2.0 - 0.5;
1148 
1149  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1150  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1151  double thisDist = sqrt(thisDiff_u * thisDiff_u + thisDiff_v * thisDiff_v);
1152 
1153  bool stopLoop = false;
1154  itnice = niceDots.begin();
1155 
1156  while (itnice != niceDots.end() && stopLoop == false) {
1157  tmpDot = *itnice;
1158 
1159  // double epsilon = 0.001; // detecte +sieurs points
1160  double epsilon = 3.0;
1161  // if the center of the dot is the same than the current
1162  // don't add it, test the next point of the grid
1163  cogTmpDot = tmpDot.getCog();
1164 
1165  if (fabs(cogTmpDot.get_u() - cogDotToTest.get_u()) < epsilon &&
1166  fabs(cogTmpDot.get_v() - cogDotToTest.get_v()) < epsilon) {
1167  stopLoop = true;
1168  // Jump all the pixels between v,u and v,
1169  // tmpDot->getFirstBorder_u()
1170  u = border_u;
1171  v = border_v;
1172  continue;
1173  }
1174 
1175  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1176  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1177  double otherDist = sqrt(otherDiff_u * otherDiff_u + otherDiff_v * otherDiff_v);
1178 
1179  // if the distance of the curent vector element to the center
1180  // is greater than the distance of this dot to the center,
1181  // then add this dot before the current vector element.
1182  if (otherDist > thisDist) {
1183  niceDots.insert(itnice, *dotToTest);
1184  ++itnice;
1185  stopLoop = true;
1186  // Jump all the pixels between v,u and v,
1187  // tmpDot->getFirstBorder_u()
1188  u = border_u;
1189  v = border_v;
1190  continue;
1191  }
1192  ++itnice;
1193  }
1194  vpTRACE(4, "End while (%d, %d)", u, v);
1195 
1196  // if we reached the end of the vector without finding the dot
1197  // or inserting it, insert it now.
1198  if (itnice == niceDots.end() && stopLoop == false) {
1199  niceDots.push_back(*dotToTest);
1200  }
1201  } else {
1202  // Store bad dots
1203  badDotsVector.push_front(*dotToTest);
1204  }
1205  }
1206  }
1207  if (dotToTest != NULL)
1208  delete dotToTest;
1209 }
1210 
1231 bool vpDot2::isValid(const vpImage<unsigned char> &I, const vpDot2 &wantedDot)
1232 {
1233  double size_precision = wantedDot.getSizePrecision();
1234  double ellipsoidShape_precision = wantedDot.getEllipsoidShapePrecision();
1235 
1236  //
1237  // First, check the width, height and surface of the dot. Those parameters
1238  // must be the same.
1239  //
1240  // if ( (wantedDot.getWidth() != 0)
1241  // && (wantedDot.getHeight() != 0)
1242  // && (wantedDot.getArea() != 0) )
1243  if ((std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon()) &&
1244  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon()) &&
1245  (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon()))
1246  // if (size_precision!=0){
1247  {
1248  if (std::fabs(size_precision) > std::numeric_limits<double>::epsilon()) {
1249  double epsilon = 0.001;
1250 #ifdef DEBUG
1251  std::cout << "test size precision......................\n";
1252  std::cout << "wanted dot: "
1253  << "w=" << wantedDot.getWidth() << " h=" << wantedDot.getHeight() << " s=" << wantedDot.getArea()
1254  << " precision=" << size_precision << " epsilon=" << epsilon << std::endl;
1255  std::cout << "dot found: "
1256  << "w=" << getWidth() << " h=" << getHeight() << " s=" << getArea() << std::endl;
1257 #endif
1258 
1259  if ((wantedDot.getWidth() * size_precision - epsilon < getWidth()) == false) {
1260  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1261 #ifdef DEBUG
1262  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1263 #endif
1264  return false;
1265  }
1266 
1267  if ((getWidth() < wantedDot.getWidth() / (size_precision + epsilon)) == false) {
1268  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1269 #ifdef DEBUG
1270  printf("Bad width %g > %g for dot (%g, %g)\n", getWidth(), wantedDot.getWidth() / (size_precision + epsilon),
1271  cog.get_u(), cog.get_v());
1272 #endif
1273  return false;
1274  }
1275 
1276  if ((wantedDot.getHeight() * size_precision - epsilon < getHeight()) == false) {
1277  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1278 #ifdef DEBUG
1279  printf("Bad height %g > %g for dot (%g, %g)\n", wantedDot.getHeight() * size_precision - epsilon, getHeight(),
1280  cog.get_u(), cog.get_v());
1281 #endif
1282  return false;
1283  }
1284 
1285  if ((getHeight() < wantedDot.getHeight() / (size_precision + epsilon)) == false) {
1286  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1287 #ifdef DEBUG
1288  printf("Bad height %g > %g for dot (%g, %g)\n", getHeight(), wantedDot.getHeight() / (size_precision + epsilon),
1289  cog.get_u(), cog.get_v());
1290 #endif
1291  return false;
1292  }
1293 
1294  if ((wantedDot.getArea() * (size_precision * size_precision) - epsilon < getArea()) == false) {
1295  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1296 #ifdef DEBUG
1297  printf("Bad surface %g > %g for dot (%g, %g)\n",
1298  wantedDot.getArea() * (size_precision * size_precision) - epsilon, getArea(), cog.get_u(), cog.get_v());
1299 #endif
1300  return false;
1301  }
1302 
1303  if ((getArea() < wantedDot.getArea() / (size_precision * size_precision + epsilon)) == false) {
1304  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1305 #ifdef DEBUG
1306  printf("Bad surface %g < %g for dot (%g, %g)\n", getArea(),
1307  wantedDot.getArea() / (size_precision * size_precision + epsilon), cog.get_u(), cog.get_v());
1308 #endif
1309  return false;
1310  }
1311  }
1312  }
1313  //
1314  // Now we can proceed to more advanced (and costy) checks.
1315  // First check there is a white (>level) elipse within dot
1316  // Then check the dot is surrounded by a black ellipse.
1317  //
1318  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1319  int nb_bad_points = 0;
1320  int nb_max_bad_points = (int)(nb_point_to_test * allowedBadPointsPercentage_);
1321  double step_angle = 2 * M_PI / nb_point_to_test;
1322 
1323  // if (ellipsoidShape_precision != 0 && compute_moment) {
1324  if (std::fabs(ellipsoidShape_precision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1325  // Chaumette, Image Moments: A General and Useful Set of Features for Visual Servoing, TRO 2004, eq 15
1326 
1327  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1328  // = m11 - m10 * m01 / m00
1329  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1330  // = m20 - m10^2 / m00
1331  // mu02 = m02 - m01^2 / m00
1332  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1333  //
1334  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1335  //
1336  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1337 
1338  // we compute parameters of the estimated ellipse
1339  double tmp1 = (m01 * m01 - m10 * m10) / m00 + (m20 - m02);
1340  double tmp2 = m11 - m10 * m01 / m00;
1341  double Sqrt = sqrt(tmp1 * tmp1 + 4 * tmp2 * tmp2);
1342  double a1 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 + Sqrt));
1343  double a2 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 - Sqrt));
1344  double alpha = 0.5 * atan2(2 * (m11 * m00 - m10 * m01), ((m20 - m02) * m00 - m10 * m10 + m01 * m01));
1345 
1346  // to be able to track small dots, minorize the ellipsoid radius for the
1347  // inner test
1348  a1 -= 1.0;
1349  a2 -= 1.0;
1350 
1351  double innerCoef = ellipsoidShape_precision;
1352  unsigned int u, v;
1353  double cog_u = this->cog.get_u();
1354  double cog_v = this->cog.get_v();
1355 
1356  vpImagePoint ip;
1357  nb_bad_points = 0;
1358  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1359  u = (unsigned int)(cog_u + innerCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1360  v = (unsigned int)(cog_v + innerCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1361  if (!this->hasGoodLevel(I, u, v)) {
1362 // vpTRACE("Inner circle pixel (%d, %d) has bad level for dot (%g, %g)",
1363 // u, v, cog_u, cog_v);
1364 #ifdef DEBUG
1365  printf("Inner circle pixel (%u, %u) has bad level for dot (%g, %g): "
1366  "%d not in [%u, %u]\n",
1367  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1368 #endif
1369  // return false;
1370  nb_bad_points++;
1371  }
1372  if (graphics) {
1373  for (unsigned int t = 0; t < thickness; t++) {
1374  ip.set_u(u + t);
1375  ip.set_v(v);
1377  }
1378  }
1379 #ifdef DEBUG
1381  vpDisplay::flush(I);
1382 #endif
1383  }
1384  if (nb_bad_points > nb_max_bad_points) {
1385 #ifdef DEBUG
1386  printf("Inner ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1387 #endif
1388  return false;
1389  }
1390  // to be able to track small dots, maximize the ellipsoid radius for the
1391  // inner test
1392  a1 += 2.0;
1393  a2 += 2.0;
1394 
1395  double outCoef = 2 - ellipsoidShape_precision; // 1.6;
1396  nb_bad_points = 0;
1397  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1398  u = (unsigned int)(cog_u + outCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1399  v = (unsigned int)(cog_v + outCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1400 #ifdef DEBUG
1401  // vpDisplay::displayRectangle(I, area, vpColor::yellow);
1402  vpDisplay::displayCross(I, (int)v, (int)u, 7, vpColor::purple);
1403  vpDisplay::flush(I);
1404 #endif
1405  // If outside the area, continue
1406  if ((double)u < area.getLeft() || (double)u > area.getRight() || (double)v < area.getTop() ||
1407  (double)v > area.getBottom()) {
1408  continue;
1409  }
1410  if (!this->hasReverseLevel(I, u, v)) {
1411 // vpTRACE("Outside circle pixel (%d, %d) has bad level for dot (%g,
1412 // %g)", u, v, cog_u, cog_v);
1413 #ifdef DEBUG
1414  printf("Outside circle pixel (%u, %u) has bad level for dot (%g, "
1415  "%g): %d not in [%u, %u]\n",
1416  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1417 #endif
1418  nb_bad_points++;
1419  // return false;
1420  }
1421  if (graphics) {
1422  for (unsigned int t = 0; t < thickness; t++) {
1423  ip.set_u(u + t);
1424  ip.set_v(v);
1425 
1427  }
1428  }
1429  }
1430  }
1431  if (nb_bad_points > nb_max_bad_points) {
1432 #ifdef DEBUG
1433  printf("Outside ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1434 #endif
1435  return false;
1436  }
1437 
1438  return true;
1439 }
1440 
1459 bool vpDot2::hasGoodLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1460 {
1461  if (!isInArea(u, v))
1462  return false;
1463 
1464  if (I[v][u] >= gray_level_min && I[v][u] <= gray_level_max) {
1465  return true;
1466  } else {
1467  return false;
1468  }
1469 }
1470 
1483 bool vpDot2::hasReverseLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1484 {
1485 
1486  if (!isInArea(u, v))
1487  return false;
1488 
1489  if (I[v][u] < gray_level_min || I[v][u] > gray_level_max) {
1490  return true;
1491  } else {
1492  return false;
1493  }
1494 }
1495 
1504 vpDot2 *vpDot2::getInstance() { return new vpDot2(); }
1505 
1521 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const { freeman_chain = direction_list; }
1522 
1523 /******************************************************************************
1524  *
1525  * PRIVATE METHODS
1526  *
1527  ******************************************************************************/
1528 
1560 bool vpDot2::computeParameters(const vpImage<unsigned char> &I, const double &_u, const double &_v)
1561 {
1562  direction_list.clear();
1563  ip_edges_list.clear();
1564 
1565  double est_u = _u; // estimated
1566  double est_v = _v;
1567 
1568  // if u has default value, set it to the actual center value
1569  // if( est_u == -1.0 )
1570  if (std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u), 1.) * std::numeric_limits<double>::epsilon()) {
1571  est_u = this->cog.get_u();
1572  }
1573 
1574  // if v has default value, set it to the actual center value
1575  // if( est_v == -1.0 )
1576  if (std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v), 1.) * std::numeric_limits<double>::epsilon()) {
1577  est_v = this->cog.get_v();
1578  }
1579 
1580  // if the estimated position of the dot is out of the image, not need to
1581  // continue, return an error tracking
1582  if (!isInArea((unsigned int)est_u, (unsigned int)est_v)) {
1583  vpDEBUG_TRACE(3,
1584  "Initial pixel coordinates (%d, %d) for dot tracking are "
1585  "not in the area",
1586  (int)est_u, (int)est_v);
1587  return false;
1588  }
1589 
1590  bbox_u_min = (int)I.getWidth();
1591  bbox_u_max = 0;
1592  bbox_v_min = (int)I.getHeight();
1593  bbox_v_max = 0;
1594 
1595  // if the first point doesn't have the right level then there's no point to
1596  // continue.
1597  if (!hasGoodLevel(I, (unsigned int)est_u, (unsigned int)est_v)) {
1598  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates", (int)est_u, (int)est_v);
1599  return false;
1600  }
1601 
1602  // find the border
1603 
1604  if (!findFirstBorder(I, (unsigned int)est_u, (unsigned int)est_v, this->firstBorder_u, this->firstBorder_v)) {
1605 
1606  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates", (int)est_u, (int)est_v);
1607  return false;
1608  }
1609 
1610  unsigned int dir = 6;
1611 
1612  // Determine the first element of the Freeman chain
1613  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
1614  unsigned int firstDir = dir;
1615 
1616  // if we are now out of the image, return an error tracking
1617  if (!isInArea(this->firstBorder_u, this->firstBorder_v)) {
1618  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area", this->firstBorder_u,
1619  this->firstBorder_v);
1620  return false;
1621  }
1622 
1623  // store the new direction and dot border coordinates.
1624  direction_list.push_back(dir);
1625  vpImagePoint ip;
1626  ip.set_u(this->firstBorder_u);
1627  ip.set_v(this->firstBorder_v);
1628 
1629  ip_edges_list.push_back(ip);
1630 
1631  int border_u = (int)this->firstBorder_u;
1632  int border_v = (int)this->firstBorder_v;
1633 
1634  // vpTRACE("-----------------------------------------");
1635  // vpTRACE("first border_u: %d border_v: %d dir: %d",
1636  // this->firstBorder_u, this->firstBorder_v,firstDir);
1637  int du, dv;
1638  float dS, dMu, dMv, dMuv, dMu2, dMv2;
1639  m00 = 0.0;
1640  m10 = 0.0;
1641  m01 = 0.0;
1642  m11 = 0.0;
1643  m20 = 0.0;
1644  m02 = 0.0;
1645  // while we didn't come back to the first point, follow the border
1646  do {
1647  // if it was asked, show the border
1648  if (graphics) {
1649  for (int t = 0; t < (int)thickness; t++) {
1650  ip.set_u(border_u + t);
1651  ip.set_v(border_v);
1652 
1654  }
1655  // vpDisplay::flush(I);
1656  }
1657 #ifdef DEBUG
1658  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1659  vpDisplay::flush(I);
1660 #endif
1661  // Determine the increments for the parameters
1662  computeFreemanParameters(border_u, border_v, dir, du, dv,
1663  dS, // surface
1664  dMu, dMv, // first order moments
1665  dMuv, dMu2, dMv2); // second order moment
1666 
1667  // Update the parameters
1668  border_u += du; // Next position on the border
1669  border_v += dv;
1670  m00 += dS; // enclosed area
1671  m10 += dMu; // First order moment along v axis
1672  m01 += dMv; // First order moment along u axis
1673  if (compute_moment) {
1674  m11 += dMuv; // Second order moment
1675  m20 += dMu2; // Second order moment along v axis
1676  m02 += dMv2; // Second order moment along u axis
1677  }
1678  // if we are now out of the image, return an error tracking
1679  if (!isInArea((unsigned int)border_u, (unsigned int)border_v)) {
1680 
1681  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
1682  // Can Occur on a single pixel dot located on the top border
1683  return false;
1684  }
1685 
1686  // store the new direction and dot border coordinates.
1687 
1688  direction_list.push_back(dir);
1689 
1690  ip.set_u(border_u);
1691  ip.set_v(border_v);
1692  ip_edges_list.push_back(ip);
1693 
1694  // vpDisplay::getClick(I);
1695 
1696  // update the extreme point of the dot.
1697  if (border_v < bbox_v_min)
1698  bbox_v_min = border_v;
1699  if (border_v > bbox_v_max)
1700  bbox_v_max = border_v;
1701  if (border_u < bbox_u_min)
1702  bbox_u_min = border_u;
1703  if (border_u > bbox_u_max)
1704  bbox_u_max = border_u;
1705 
1706  // move around the tracked entity by following the border.
1707  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
1708  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)", border_u, border_v);
1709  return false;
1710  }
1711 
1712  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v,
1713  // dir);
1714 
1715  } while ((getFirstBorder_u() != (unsigned int)border_u || getFirstBorder_v() != (unsigned int)border_v ||
1716  firstDir != dir) &&
1717  isInArea((unsigned int)border_u, (unsigned int)border_v));
1718 
1719 #ifdef VP_DEBUG
1720 #if VP_DEBUG_MODE == 3
1721  vpDisplay::flush(I);
1722 #endif
1723 #endif
1724 
1725  // if the surface is one or zero , the center of gravity wasn't properly
1726  // detected. Return an error tracking.
1727  // if( m00 == 0 || m00 == 1 )
1728  if (std::fabs(m00) <= std::numeric_limits<double>::epsilon() ||
1729  std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.) * std::numeric_limits<double>::epsilon()) {
1730  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
1731  return false;
1732  } else // compute the center
1733  {
1734  // this magic formula gives the coordinates of the center of gravity
1735  double tmpCenter_u = m10 / m00;
1736  double tmpCenter_v = m01 / m00;
1737 
1738  // Updates the second order centered moments
1739  if (compute_moment) {
1740  mu11 = m11 - tmpCenter_u * m01;
1741  mu02 = m02 - tmpCenter_v * m01;
1742  mu20 = m20 - tmpCenter_u * m10;
1743  }
1744 
1745  // check the center is in the image... never know...
1746  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
1747  // (unsigned int)tmpCenter_v ) )
1748  // {
1749  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has
1750  // not a good in level", tmpCenter_u, tmpCenter_v); return false;
1751  // }
1752 
1753  cog.set_u(tmpCenter_u);
1754  cog.set_v(tmpCenter_v);
1755  }
1756 
1757  width = bbox_u_max - bbox_u_min + 1;
1758  height = bbox_v_max - bbox_v_min + 1;
1759  surface = m00;
1760 
1761  computeMeanGrayLevel(I);
1762  return true;
1763 }
1764 
1780 bool vpDot2::findFirstBorder(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1781  unsigned int &border_u, unsigned int &border_v)
1782 {
1783  // find the border
1784 
1785  // NOTE:
1786  // from here we use int and not double. This is because we don't have
1787  // rounding problems and it's actually more a trouble than smth else to
1788  // work with double when navigating around the dot.
1789  border_u = u;
1790  border_v = v;
1791  double epsilon = 0.001;
1792 
1793 #ifdef DEBUG
1794  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
1795 #endif
1796  while (hasGoodLevel(I, border_u + 1, border_v) && border_u < area.getRight() /*I.getWidth()*/) {
1797  // if the width of this dot was initialised and we already crossed the dot
1798  // on more than the max possible width, no need to continue, return an
1799  // error tracking
1800  if (getWidth() > 0 && (border_u - u) > getWidth() / (getMaxSizeSearchDistancePrecision() + epsilon)) {
1801  vpDEBUG_TRACE(3,
1802  "The found dot (%d, %d, %d) has a greater width than the "
1803  "required one",
1804  u, v, border_u);
1805  return false;
1806  }
1807 #ifdef DEBUG
1808  vpDisplay::displayPoint(I, (int)border_v, (int)border_u + 1, vpColor::green);
1809  vpDisplay::flush(I);
1810 #endif
1811 
1812  border_u++;
1813  }
1814  return true;
1815 }
1816 
1835 bool vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1836  unsigned int &element)
1837 {
1838 
1839  if (hasGoodLevel(I, u, v)) {
1840  unsigned int _u = u;
1841  unsigned int _v = v;
1842  // get the point on the right of the point passed in
1843  updateFreemanPosition(_u, _v, (element + 2) % 8);
1844  if (hasGoodLevel(I, _u, _v)) {
1845  element = (element + 2) % 8; // turn right
1846  } else {
1847  unsigned int _u1 = u;
1848  unsigned int _v1 = v;
1849  updateFreemanPosition(_u1, _v1, (element + 1) % 8);
1850 
1851  if (hasGoodLevel(I, _u1, _v1)) {
1852  element = (element + 1) % 8; // turn diag right
1853  } else {
1854  unsigned int _u2 = u;
1855  unsigned int _v2 = v;
1856  updateFreemanPosition(_u2, _v2, element); // same direction
1857 
1858  if (hasGoodLevel(I, _u2, _v2)) {
1859  // element = element; // keep same dir
1860  } else {
1861  unsigned int _u3 = u;
1862  unsigned int _v3 = v;
1863  updateFreemanPosition(_u3, _v3, (element + 7) % 8); // diag left
1864 
1865  if (hasGoodLevel(I, _u3, _v3)) {
1866  element = (element + 7) % 8; // turn diag left
1867  } else {
1868  unsigned int _u4 = u;
1869  unsigned int _v4 = v;
1870  updateFreemanPosition(_u4, _v4, (element + 6) % 8); // left
1871 
1872  if (hasGoodLevel(I, _u4, _v4)) {
1873  element = (element + 6) % 8; // turn left
1874  } else {
1875  unsigned int _u5 = u;
1876  unsigned int _v5 = v;
1877  updateFreemanPosition(_u5, _v5, (element + 5) % 8); // left
1878 
1879  if (hasGoodLevel(I, _u5, _v5)) {
1880  element = (element + 5) % 8; // turn diag down
1881  } else {
1882  unsigned int _u6 = u;
1883  unsigned int _v6 = v;
1884  updateFreemanPosition(_u6, _v6, (element + 4) % 8); // left
1885 
1886  if (hasGoodLevel(I, _u6, _v6)) {
1887  element = (element + 4) % 8; // turn down
1888  } else {
1889  unsigned int _u7 = u;
1890  unsigned int _v7 = v;
1891  updateFreemanPosition(_u7, _v7, (element + 3) % 8); // diag
1892 
1893  if (hasGoodLevel(I, _u7, _v7)) {
1894  element = (element + 3) % 8; // turn diag right down
1895  } else {
1896  // No neighbor with a good level
1897  //
1898  return false;
1899  }
1900  }
1901  }
1902  }
1903  }
1904  }
1905  }
1906  }
1907  }
1908 
1909  else {
1910  return false;
1911  }
1912 
1913  return true;
1914 }
1915 
1947 void vpDot2::computeFreemanParameters(const int &u_p, const int &v_p, unsigned int &element, int &du, int &dv,
1948  float &dS, float &dMu, float &dMv, float &dMuv, float &dMu2, float &dMv2)
1949 {
1950  du = 0;
1951  dv = 0;
1952  dMuv = 0;
1953  dMu2 = 0;
1954  dMv2 = 0;
1955 
1956  /*
1957  3 2 1
1958  \ | /
1959  \|/
1960  4 ------- 0
1961  /|\
1962  / | \
1963  5 6 7
1964  */
1965  switch (element) {
1966  case 0: // go right
1967  du = 1;
1968  dS = (float)v_p;
1969  dMu = 0.0;
1970  dMv = (float)(0.5 * v_p * v_p);
1971  if (compute_moment) {
1972  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
1973  dMu2 = 0;
1974  dMv2 = (float)(1.0 / 3. * v_p * v_p * v_p);
1975  }
1976  break;
1977 
1978  case 1: // go right top
1979  du = 1;
1980  dv = 1;
1981  dS = (float)(v_p + 0.5);
1982  dMu = -(float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
1983  dMv = (float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
1984  if (compute_moment) {
1985  float half_u_p = (float)(0.5 * u_p);
1986  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) + v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
1987  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1. / 12.0);
1988  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1. / 12.0);
1989  }
1990  break;
1991 
1992  case 2: // go top
1993  dv = 1;
1994  dS = 0.0;
1995  dMu = (float)(-0.5 * u_p * u_p);
1996  dMv = 0.0;
1997  if (compute_moment) {
1998  dMuv = 0;
1999  dMu2 = (float)(-1.0 / 3. * u_p * u_p * u_p);
2000  dMv2 = 0;
2001  }
2002  break;
2003 
2004  case 3:
2005  du = -1;
2006  dv = 1;
2007  dS = (float)(-v_p - 0.5);
2008  dMu = -(float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2009  dMv = -(float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
2010  if (compute_moment) {
2011  float half_u_p = (float)(0.5 * u_p);
2012  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) + v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2013  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2014  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1. / 12.0);
2015  }
2016  break;
2017 
2018  case 4:
2019  du = -1;
2020  dS = (float)(-v_p);
2021  dMv = (float)(-0.5 * v_p * v_p);
2022  dMu = 0.0;
2023  if (compute_moment) {
2024  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2025  dMu2 = 0;
2026  dMv2 = (float)(-1.0 / 3. * v_p * v_p * v_p);
2027  }
2028  break;
2029 
2030  case 5:
2031  du = -1;
2032  dv = -1;
2033  dS = (float)(-v_p + 0.5);
2034  dMu = (float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2035  dMv = (float)(-(0.5 * v_p * (v_p - 1) + 1.0 / 6.0));
2036  if (compute_moment) {
2037  float half_u_p = (float)(0.5 * u_p);
2038  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) - v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2039  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2040  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2041  }
2042  break;
2043 
2044  case 6:
2045  dv = -1;
2046  dS = 0.0;
2047  dMu = (float)(0.5 * u_p * u_p);
2048  dMv = 0.0;
2049  if (compute_moment) {
2050  dMuv = 0;
2051  dMu2 = (float)(1.0 / 3. * u_p * u_p * u_p);
2052  dMv2 = 0;
2053  }
2054  break;
2055 
2056  case 7:
2057  du = 1;
2058  dv = -1;
2059  dS = (float)(v_p - 0.5);
2060  dMu = (float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
2061  dMv = (float)(0.5 * v_p * (v_p - 1) + 1.0 / 6.0);
2062  if (compute_moment) {
2063  float half_u_p = (float)(0.5 * u_p);
2064  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) - v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
2065  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1. / 12.0);
2066  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2067  }
2068  break;
2069  }
2070 }
2071 
2085 void vpDot2::updateFreemanPosition(unsigned int &u, unsigned int &v, const unsigned int &dir)
2086 {
2087  switch (dir) {
2088  case 0:
2089  u += 1;
2090  break;
2091  case 1:
2092  u += 1;
2093  v += 1;
2094  break;
2095  case 2:
2096  v += 1;
2097  break;
2098  case 3:
2099  u -= 1;
2100  v += 1;
2101  break;
2102  case 4:
2103  u -= 1;
2104  break;
2105  case 5:
2106  u -= 1;
2107  v -= 1;
2108  break;
2109  case 6:
2110  v -= 1;
2111  break;
2112  case 7:
2113  u += 1;
2114  v -= 1;
2115  break;
2116  }
2117 }
2118 
2130 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const { return isInImage(I, cog); }
2131 
2143 bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
2144 {
2145  unsigned int h = I.getHeight();
2146  unsigned int w = I.getWidth();
2147  double u = ip.get_u();
2148  double v = ip.get_v();
2149 
2150  if (u < 0 || u >= w)
2151  return false;
2152  if (v < 0 || v >= h)
2153  return false;
2154  return true;
2155 }
2156 
2168 bool vpDot2::isInArea(const unsigned int &u, const unsigned int &v) const
2169 {
2170  unsigned int area_u_min = (unsigned int)area.getLeft();
2171  unsigned int area_u_max = (unsigned int)area.getRight();
2172  unsigned int area_v_min = (unsigned int)area.getTop();
2173  unsigned int area_v_max = (unsigned int)area.getBottom();
2174 
2175  if (u < area_u_min || u > area_u_max)
2176  return false;
2177  if (v < area_v_min || v > area_v_max)
2178  return false;
2179  return true;
2180 }
2181 
2193 void vpDot2::getGridSize(unsigned int &gridWidth, unsigned int &gridHeight)
2194 {
2195  // first get the research grid width and height Note that
2196  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2197  // contained in the dot. We gent this here if the dot is a perfect disc.
2198  // More accurate criterium to define the grid should be implemented if
2199  // necessary
2200  gridWidth = (unsigned int)(getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2201  gridHeight = (unsigned int)(getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2202 
2203  if (gridWidth == 0)
2204  gridWidth = 1;
2205  if (gridHeight == 0)
2206  gridHeight = 1;
2207 }
2208 
2221 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char> &I)
2222 {
2223  int cog_u = (int)cog.get_u();
2224  int cog_v = (int)cog.get_v();
2225 
2226  unsigned int sum_value = 0;
2227  unsigned int nb_pixels = 0;
2228 
2229  for (unsigned int i = (unsigned int)this->bbox_u_min; i <= (unsigned int)this->bbox_u_max; i++) {
2230  unsigned int pixel_gray = (unsigned int)I[(unsigned int)cog_v][i];
2231  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2232  sum_value += pixel_gray;
2233  nb_pixels++;
2234  }
2235  }
2236  for (unsigned int i = (unsigned int)this->bbox_v_min; i <= (unsigned int)this->bbox_v_max; i++) {
2237  unsigned char pixel_gray = I[i][(unsigned int)cog_u];
2238  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2239  sum_value += pixel_gray;
2240  nb_pixels++;
2241  }
2242  }
2243  if (nb_pixels < 10) { // could be good to choose the min nb points from area of dot
2244  // add diagonals points to have enough point
2245  int imin, imax;
2246  if ((cog_u - bbox_u_min) > (cog_v - bbox_v_min)) {
2247  imin = cog_v - bbox_v_min;
2248  } else {
2249  imin = cog_u - bbox_u_min;
2250  }
2251  if ((bbox_u_max - cog_u) > (bbox_v_max - cog_v)) {
2252  imax = bbox_v_max - cog_v;
2253  } else {
2254  imax = bbox_u_max - cog_u;
2255  }
2256  for (int i = -imin; i <= imax; i++) {
2257  unsigned int pixel_gray = (unsigned int)I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2258  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2259  sum_value += pixel_gray;
2260  nb_pixels++;
2261  }
2262  }
2263 
2264  if ((cog_u - bbox_u_min) > (bbox_v_max - cog_v)) {
2265  imin = bbox_v_max - cog_v;
2266  } else {
2267  imin = cog_u - bbox_u_min;
2268  }
2269  if ((bbox_u_max - cog_u) > (cog_v - bbox_v_min)) {
2270  imax = cog_v - bbox_v_min;
2271  } else {
2272  imax = bbox_u_max - cog_u;
2273  }
2274 
2275  for (int i = -imin; i <= imax; i++) {
2276  unsigned char pixel_gray = I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2277  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2278  sum_value += pixel_gray;
2279  nb_pixels++;
2280  }
2281  }
2282  }
2283 
2284  if (nb_pixels == 0) {
2285  // should never happen
2286  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No point was found"));
2287  } else {
2288  mean_gray_level = sum_value / nb_pixels;
2289  }
2290 }
2291 
2310 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I,
2311  vpColor col, bool trackDot)
2312 {
2313  vpMatrix Cogs(n, 2);
2314  vpImagePoint cog;
2315  unsigned int i;
2316  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
2317  if (fromFile) {
2318  vpMatrix::loadMatrix(dotFile, Cogs);
2319  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
2320  }
2321 
2322  // test number of cogs in file
2323  if (Cogs.getRows() < n) {
2324  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
2325  fromFile = false;
2326  }
2327 
2328  // read from file and tracks the dots
2329  if (fromFile) {
2330  try {
2331  for (i = 0; i < n; ++i) {
2332  cog.set_uv(Cogs[i][0], Cogs[i][1]);
2333  dot[i].setGraphics(true);
2334  dot[i].setCog(cog);
2335  if (trackDot) {
2336  dot[i].initTracking(I, cog);
2337  dot[i].track(I);
2338  vpDisplay::displayCross(I, cog, 10, col);
2339  }
2340  }
2341  } catch (...) {
2342  std::cout << "Cannot track dots from file" << std::endl;
2343  fromFile = false;
2344  }
2345  vpDisplay::flush(I);
2346 
2347  // check that dots are far away ones from the other
2348  for (i = 0; i < n && fromFile; ++i) {
2349  double d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
2350  for (unsigned int j = 0; j < n && fromFile; ++j)
2351  if (j != i)
2352  if (dot[i].getDistance(dot[j]) < d) {
2353  fromFile = false;
2354  std::cout << "Dots from file seem incoherent" << std::endl;
2355  }
2356  }
2357  }
2358 
2359  if (!fromFile) {
2360  vpDisplay::display(I);
2361  vpDisplay::flush(I);
2362 
2363  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
2364  for (i = 0; i < n; i++) {
2365  if (trackDot) {
2366  dot[i].setGraphics(true);
2367  dot[i].initTracking(I);
2368  cog = dot[i].getCog();
2369  } else {
2370  vpDisplay::getClick(I, cog);
2371  dot[i].setCog(cog);
2372  }
2373  Cogs[i][0] = cog.get_u();
2374  Cogs[i][1] = cog.get_v();
2375  vpDisplay::displayCross(I, cog, 10, col);
2376  vpDisplay::flush(I);
2377  }
2378  }
2379 
2380  if (!fromFile && (dotFile != "")) {
2381  vpMatrix::saveMatrix(dotFile, Cogs);
2382  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
2383  }
2384 
2385  // back to non graphic mode
2386  for (i = 0; i < n; ++i)
2387  dot[i].setGraphics(false);
2388 
2389  return Cogs;
2390 }
2391 
2408 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I,
2409  std::vector<vpImagePoint> &cogs, vpImagePoint *cogStar)
2410 {
2411  unsigned int i;
2412  // tracking
2413  for (i = 0; i < n; ++i) {
2414  dot[i].track(I);
2415  cogs.push_back(dot[i].getCog());
2416  }
2417  // trajectories
2418  for (i = n; i < cogs.size(); ++i)
2419  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::green, true);
2420  // initial position
2421  for (i = 0; i < n; ++i)
2422  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::blue, true);
2423  // if exists, desired position
2424  if (cogStar != NULL)
2425  for (i = 0; i < n; ++i) {
2426  vpDisplay::displayDotLine(I, cogStar[i], dot[i].getCog(), vpColor::red);
2427  vpDisplay::displayCircle(I, cogStar[i], 4, vpColor::red, true);
2428  }
2429  vpDisplay::flush(I);
2430 }
2431 
2447  const std::list<vpImagePoint> &edges_list, vpColor color, unsigned int thickness)
2448 {
2449  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2450  std::list<vpImagePoint>::const_iterator it;
2451 
2452  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2453  vpDisplay::displayPoint(I, *it, color);
2454  }
2455 }
2456 
2471 void vpDot2::display(const vpImage<vpRGBa> &I, const vpImagePoint &cog, const std::list<vpImagePoint> &edges_list,
2472  vpColor color, unsigned int thickness)
2473 {
2474  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2475  std::list<vpImagePoint>::const_iterator it;
2476 
2477  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2478  vpDisplay::displayPoint(I, *it, color);
2479  }
2480 }
2481 
2487 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:494
unsigned int getRows() const
Definition: vpArray2D.h:291
Class to define RGB colors available for display functionnalities.
Definition: vpColor.h:158
static const vpColor red
Definition: vpColor.h:217
static const vpColor blue
Definition: vpColor.h:223
static const vpColor purple
Definition: vpColor.h:228
static const vpColor green
Definition: vpColor.h:220
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
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)
static void displayCircle(const vpImage< unsigned char > &I, const vpImagePoint &center, unsigned int radius, 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:127
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:220
vpDot2()
Definition: vpDot2.cpp:104
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:226
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:2408
void track(const vpImage< unsigned char > &I, bool canMakeTheWindowGrow=true)
Definition: vpDot2.cpp:442
double m02
Definition: vpDot2.h:415
double m01
Definition: vpDot2.h:391
virtual ~vpDot2()
Definition: vpDot2.cpp:198
void setGraphics(bool activate)
Definition: vpDot2.h:314
double mu11
Definition: vpDot2.h:424
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:834
vpDot2 & operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:147
void setGraphicsThickness(unsigned int t)
Definition: vpDot2.h:321
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:661
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:980
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1) const
Definition: vpDot2.cpp:212
double m20
Definition: vpDot2.h:406
double m00
Definition: vpDot2.h:375
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:351
double getArea() const
Definition: vpDot2.cpp:638
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:764
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:736
double m11
Definition: vpDot2.h:399
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:334
void getFreemanChain(std::list< unsigned int > &freeman_chain) const
Definition: vpDot2.cpp:1521
void setHeight(const double &height)
Definition: vpDot2.cpp:705
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:669
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:260
vpImagePoint getCog() const
Definition: vpDot2.h:180
double m10
Definition: vpDot2.h:383
double getSizePrecision() const
Definition: vpDot2.cpp:652
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:645
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:290
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:674
double mu02
Definition: vpDot2.h:434
void setWidth(const double &width)
Definition: vpDot2.cpp:693
double mu20
Definition: vpDot2.h:429
double getWidth() const
Definition: vpDot2.cpp:624
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:807
double getMeanGrayLevel() const
Definition: vpDot2.h:234
void setArea(const double &area)
Definition: vpDot2.cpp:717
void setComputeMoments(bool activate)
Definition: vpDot2.h:276
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:253
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:2310
double getHeight() const
Definition: vpDot2.cpp:631
error that can be emited by ViSP classes.
Definition: vpException.h:72
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:89
double get_j() const
Definition: vpImagePoint.h:132
double get_u() const
Definition: vpImagePoint.h:143
void set_u(double u)
Definition: vpImagePoint.h:335
void set_uv(double u, double v)
Definition: vpImagePoint.h:357
void set_v(double v)
Definition: vpImagePoint.h:346
double get_i() const
Definition: vpImagePoint.h:121
double get_v() const
Definition: vpImagePoint.h:154
unsigned int getWidth() const
Definition: vpImage.h:246
unsigned int getHeight() const
Definition: vpImage.h:188
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:810
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:171
static double sqr(double x)
Definition: vpMath.h:123
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:154
static bool loadMatrix(const std::string &filename, vpArray2D< double > &M, bool binary=false, char *header=NULL)
Definition: vpMatrix.h:717
static bool saveMatrix(const std::string &filename, const vpArray2D< double > &M, bool binary=false, const char *header="")
Definition: vpMatrix.h:752
Defines a rectangle in the plane.
Definition: vpRect.h:80
double getLeft() const
Definition: vpRect.h:174
void setRect(double l, double t, double w, double h)
Definition: vpRect.h:334
double getRight() const
Definition: vpRect.h:180
double getBottom() const
Definition: vpRect.h:98
double getTop() const
Definition: vpRect.h:193
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:65
Error that can be emited by the vpTracker class and its derivates.
#define vpTRACE
Definition: vpDebug.h:416
#define vpDEBUG_TRACE
Definition: vpDebug.h:487