Visual Servoing Platform  version 3.3.0 under development (2020-02-17)
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  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  // else {
532  // // test if the found dot is valid,
533  // if( ! isValid( I, wantedDot ) ) {
534  // *this = wantedDot;
535  // vpERROR_TRACE("The found dot is invalid:",
536  // "- could be a problem of size (width or height) or "
537  // " surface (number of pixels) which differ too much "
538  // " to the previous one "
539  // "- or a problem of the shape which is not ellipsoid if "
540  // " use setEllipsoidShapePrecision(double
541  // ellipsoidShapePrecision) "
542  // " which is the default case. "
543  // " To track a non ellipsoid shape use
544  // setEllipsoidShapePrecision(0)") ;
545  // throw(vpTrackingException(vpTrackingException::featureLostError,
546  // "The found dot is invalid")) ;
547  // }
548  // }
549 
550  // if this dot is partially out of the image, return an error tracking.
551  if (!isInImage(I)) {
552  // vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
554  "The center of gravity of the dot is not in the image"));
555  }
556 
557  // Get dots center of gravity
558  // unsigned int u = (unsigned int) this->cog.get_u();
559  // unsigned int v = (unsigned int) this->cog.get_v();
560  // Updates the min and max gray levels for the next iteration
561  // double Ip = pow((double)I[v][u]/255,1/gamma);
562  double Ip = pow(getMeanGrayLevel() / 255, 1 / gamma);
563  // printf("current value of gray level center : %i\n", I[v][u]);
564 
565  // getMeanGrayLevel(I);
566  if (Ip - (1 - grayLevelPrecision) < 0) {
567  gray_level_min = 0;
568  } else {
569  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
570  if (gray_level_min > 255)
571  gray_level_min = 255;
572  }
573  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
574  if (gray_level_max > 255)
575  gray_level_max = 255;
576 
577  // printf("%i %i \n",gray_level_max,gray_level_min);
578  if (graphics) {
579  // display a red cross at the center of gravity's location in the image.
580 
581  vpDisplay::displayCross(I, this->cog, 3 * thickness + 8, vpColor::red, thickness);
582  // vpDisplay::flush(I);
583  }
584 }
585 
608 void vpDot2::track(const vpImage<unsigned char> &I, vpImagePoint &ip, bool canMakeTheWindowGrow)
609 {
610  track(I, canMakeTheWindowGrow);
611 
612  ip = this->cog;
613 }
614 
617 
623 double vpDot2::getWidth() const { return width; }
624 
630 double vpDot2::getHeight() const { return height; }
631 
637 double vpDot2::getArea() const { return fabs(surface); }
638 
644 double vpDot2::getGrayLevelPrecision() const { return grayLevelPrecision; }
645 
651 double vpDot2::getSizePrecision() const { return sizePrecision; }
652 
660 double vpDot2::getEllipsoidShapePrecision() const { return ellipsoidShapePrecision; }
661 
668 double vpDot2::getMaxSizeSearchDistancePrecision() const { return maxSizeSearchDistancePrecision; }
669 
673 double vpDot2::getDistance(const vpDot2 &distantDot) const
674 {
675  vpImagePoint cogDistantDot = distantDot.getCog();
676  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
677  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
678  return sqrt(diff_u * diff_u + diff_v * diff_v);
679 }
680 
682 
692 void vpDot2::setWidth(const double &w) { this->width = w; }
693 
704 void vpDot2::setHeight(const double &h) { this->height = h; }
705 
716 void vpDot2::setArea(const double &a) { this->surface = a; }
717 
735 void vpDot2::setGrayLevelPrecision(const double &precision)
736 {
737  double epsilon = 0.05;
738  if (grayLevelPrecision < epsilon) {
739  this->grayLevelPrecision = epsilon;
740  } else if (grayLevelPrecision > 1) {
741  this->grayLevelPrecision = 1.0;
742  } else {
743  this->grayLevelPrecision = precision;
744  }
745 }
763 void vpDot2::setSizePrecision(const double &precision)
764 {
765  if (sizePrecision < 0) {
766  this->sizePrecision = 0;
767  } else if (sizePrecision > 1) {
768  this->sizePrecision = 1.0;
769  } else {
770  this->sizePrecision = precision;
771  }
772 }
773 
806 void vpDot2::setEllipsoidShapePrecision(const double &precision)
807 {
808 
809  if (ellipsoidShapePrecision < 0) {
810  this->ellipsoidShapePrecision = 0;
811  } else if (ellipsoidShapePrecision > 1) {
812  this->ellipsoidShapePrecision = 1.0;
813  } else {
814  this->ellipsoidShapePrecision = precision;
815  }
816 }
817 
833 void vpDot2::setMaxSizeSearchDistancePrecision(const double &precision)
834 {
835  double epsilon = 0.05;
836  if (maxSizeSearchDistancePrecision < epsilon) {
837  this->maxSizeSearchDistancePrecision = epsilon;
838  } else if (maxSizeSearchDistancePrecision > 1) {
839  this->maxSizeSearchDistancePrecision = 1.0;
840  } else {
841  this->maxSizeSearchDistancePrecision = precision;
842  }
843 }
844 
853 void vpDot2::setArea(const vpImage<unsigned char> &I) { setArea(I, 0, 0, I.getWidth(), I.getHeight()); }
854 
867 void vpDot2::setArea(const vpImage<unsigned char> &I, int u, int v, unsigned int w, unsigned int h)
868 {
869  unsigned int image_w = I.getWidth();
870  unsigned int image_h = I.getHeight();
871 
872  // Bounds the area to the image
873  if (u < 0)
874  u = 0;
875  else if (u >= (int)image_w)
876  u = (int)image_w - 1;
877  if (v < 0)
878  v = 0;
879  else if (v >= (int)image_h)
880  v = (int)image_h - 1;
881 
882  if (((unsigned int)u + w) > image_w)
883  w = image_w - (unsigned int)u - 1;
884  if (((unsigned int)v + h) > image_h)
885  h = image_h - (unsigned int)v - 1;
886 
887  area.setRect(u, v, w, h);
888 }
889 
897 void vpDot2::setArea(const vpRect &a) { area = a; }
898 
900 
952 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, std::list<vpDot2> &niceDots)
953 {
954  searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
955 }
956 
979 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, int area_u, int area_v, unsigned int area_w,
980  unsigned int area_h, std::list<vpDot2> &niceDots)
981 
982 {
983  // clear the list of nice dots
984  niceDots.clear();
985 
986  // Fit the input area in the image; we keep only the common part between
987  // this area and the image.
988  setArea(I, area_u, area_v, area_w, area_h);
989 
990  // compute the size of the search grid
991  unsigned int gridWidth;
992  unsigned int gridHeight;
993  getGridSize(gridWidth, gridHeight);
994 
995  if (graphics) {
996  // Display the area were the dot is search
997  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
998  // vpDisplay::flush(I);
999  }
1000 
1001 #ifdef DEBUG
1003  vpDisplay::flush(I);
1004 #endif
1005  // start the search loop; for all points of the search grid,
1006  // test if the pixel belongs to a valid dot.
1007  // if it is so eventually add it to the vector of valid dots.
1008  std::list<vpDot2> badDotsVector;
1009  std::list<vpDot2>::iterator itnice;
1010  std::list<vpDot2>::iterator itbad;
1011 
1012  vpDot2 *dotToTest = NULL;
1013  vpDot2 tmpDot;
1014 
1015  unsigned int area_u_min = (unsigned int)area.getLeft();
1016  unsigned int area_u_max = (unsigned int)area.getRight();
1017  unsigned int area_v_min = (unsigned int)area.getTop();
1018  unsigned int area_v_max = (unsigned int)area.getBottom();
1019 
1020  unsigned int u, v;
1021  vpImagePoint cogTmpDot;
1022 
1023  for (v = area_v_min; v < area_v_max; v = v + gridHeight) {
1024  for (u = area_u_min; u < area_u_max; u = u + gridWidth) {
1025  // if the pixel we're in doesn't have the right color (outside the
1026  // graylevel interval), no need to check further, just get to the
1027  // next grid intersection.
1028  if (!hasGoodLevel(I, u, v))
1029  continue;
1030 
1031  // Test if an other germ is inside the bounding box of a dot previously
1032  // detected
1033  bool good_germ = true;
1034 
1035  itnice = niceDots.begin();
1036  while (itnice != niceDots.end() && good_germ == true) {
1037  tmpDot = *itnice;
1038 
1039  cogTmpDot = tmpDot.getCog();
1040  double u0 = cogTmpDot.get_u();
1041  double v0 = cogTmpDot.get_v();
1042  double half_w = tmpDot.getWidth() / 2.;
1043  double half_h = tmpDot.getHeight() / 2.;
1044 
1045  if (u >= (u0 - half_w) && u <= (u0 + half_w) && v >= (v0 - half_h) && v <= (v0 + half_h)) {
1046  // Germ is in a previously detected dot
1047  good_germ = false;
1048  }
1049  ++itnice;
1050  }
1051 
1052  if (!good_germ)
1053  continue;
1054 
1055  // Compute the right border position for this possible germ
1056  unsigned int border_u;
1057  unsigned int border_v;
1058  if (findFirstBorder(I, u, v, border_u, border_v) == false) {
1059  // germ is not good.
1060  // Jump all the pixels between v,u and v,
1061  // dotToTest->getFirstBorder_u()
1062  u = border_u;
1063  v = border_v;
1064  continue;
1065  }
1066 
1067  itbad = badDotsVector.begin();
1068 #define vpBAD_DOT_VALUE (*itbad)
1069  vpImagePoint cogBadDot;
1070 
1071  while (itbad != badDotsVector.end() && good_germ == true) {
1072  if ((double)u >= vpBAD_DOT_VALUE.bbox_u_min && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1073  (double)v >= vpBAD_DOT_VALUE.bbox_v_min && (double)v <= vpBAD_DOT_VALUE.bbox_v_max) {
1074  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1075  while (it_edges != ip_edges_list.end() && good_germ == true) {
1076  // Test if the germ belong to a previously detected dot:
1077  // - from the germ go right to the border and compare this
1078  // position to the list of pixels of previously detected dots
1079  cogBadDot = *it_edges;
1080  // if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1081  if ((std::fabs(border_u - cogBadDot.get_u()) <=
1082  vpMath::maximum(std::fabs((double)border_u), std::fabs(cogBadDot.get_u())) *
1083  std::numeric_limits<double>::epsilon()) &&
1084  (std::fabs(v - cogBadDot.get_v()) <=
1085  vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v())) *
1086  std::numeric_limits<double>::epsilon())) {
1087  good_germ = false;
1088  }
1089  ++it_edges;
1090  }
1091  }
1092  ++itbad;
1093  }
1094 #undef vpBAD_DOT_VALUE
1095 
1096  if (!good_germ) {
1097  // Jump all the pixels between v,u and v,
1098  // dotToTest->getFirstBorder_u()
1099  u = border_u;
1100  v = border_v;
1101  continue;
1102  }
1103 
1104  vpTRACE(4, "Try germ (%d, %d)", u, v);
1105 
1106  vpImagePoint germ;
1107  germ.set_u(u);
1108  germ.set_v(v);
1109 
1110  // otherwise estimate the width, height and surface of the dot we
1111  // created, and test it.
1112  if (dotToTest != NULL)
1113  delete dotToTest;
1114  dotToTest = getInstance();
1115  dotToTest->setCog(germ);
1116  dotToTest->setGrayLevelMin(getGrayLevelMin());
1117  dotToTest->setGrayLevelMax(getGrayLevelMax());
1119  dotToTest->setSizePrecision(getSizePrecision());
1120  dotToTest->setGraphics(graphics);
1121  dotToTest->setGraphicsThickness(thickness);
1122  dotToTest->setComputeMoments(true);
1123  dotToTest->setArea(area);
1124  dotToTest->setEllipsoidShapePrecision(ellipsoidShapePrecision);
1125  dotToTest->setEllipsoidBadPointsPercentage(allowedBadPointsPercentage_);
1126 
1127  // first compute the parameters of the dot.
1128  // if for some reasons this caused an error tracking
1129  // (dot partially out of the image...), check the next intersection
1130  if (dotToTest->computeParameters(I) == false) {
1131  // Jump all the pixels between v,u and v,
1132  // dotToTest->getFirstBorder_u()
1133  u = border_u;
1134  v = border_v;
1135  continue;
1136  }
1137  // if the dot to test is valid,
1138  if (dotToTest->isValid(I, *this)) {
1139  vpImagePoint cogDotToTest = dotToTest->getCog();
1140  // Compute the distance to the center. The center used here is not the
1141  // area center available by area.getCenter(area_center_u,
1142  // area_center_v) but the center of the input area which may be
1143  // partially outside the image.
1144 
1145  double area_center_u = area_u + area_w / 2.0 - 0.5;
1146  double area_center_v = area_v + area_h / 2.0 - 0.5;
1147 
1148  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1149  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1150  double thisDist = sqrt(thisDiff_u * thisDiff_u + thisDiff_v * thisDiff_v);
1151 
1152  bool stopLoop = false;
1153  itnice = niceDots.begin();
1154 
1155  while (itnice != niceDots.end() && stopLoop == false) {
1156  tmpDot = *itnice;
1157 
1158  // double epsilon = 0.001; // detecte +sieurs points
1159  double epsilon = 3.0;
1160  // if the center of the dot is the same than the current
1161  // don't add it, test the next point of the grid
1162  cogTmpDot = tmpDot.getCog();
1163 
1164  if (fabs(cogTmpDot.get_u() - cogDotToTest.get_u()) < epsilon &&
1165  fabs(cogTmpDot.get_v() - cogDotToTest.get_v()) < epsilon) {
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 
1174  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1175  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1176  double otherDist = sqrt(otherDiff_u * otherDiff_u + otherDiff_v * otherDiff_v);
1177 
1178  // if the distance of the curent vector element to the center
1179  // is greater than the distance of this dot to the center,
1180  // then add this dot before the current vector element.
1181  if (otherDist > thisDist) {
1182  niceDots.insert(itnice, *dotToTest);
1183  ++itnice;
1184  stopLoop = true;
1185  // Jump all the pixels between v,u and v,
1186  // tmpDot->getFirstBorder_u()
1187  u = border_u;
1188  v = border_v;
1189  continue;
1190  }
1191  ++itnice;
1192  }
1193  vpTRACE(4, "End while (%d, %d)", u, v);
1194 
1195  // if we reached the end of the vector without finding the dot
1196  // or inserting it, insert it now.
1197  if (itnice == niceDots.end() && stopLoop == false) {
1198  niceDots.push_back(*dotToTest);
1199  }
1200  } else {
1201  // Store bad dots
1202  badDotsVector.push_front(*dotToTest);
1203  }
1204  }
1205  }
1206  if (dotToTest != NULL)
1207  delete dotToTest;
1208 }
1209 
1230 bool vpDot2::isValid(const vpImage<unsigned char> &I, const vpDot2 &wantedDot)
1231 {
1232  double size_precision = wantedDot.getSizePrecision();
1233  double ellipsoidShape_precision = wantedDot.getEllipsoidShapePrecision();
1234 
1235  //
1236  // First, check the width, height and surface of the dot. Those parameters
1237  // must be the same.
1238  //
1239  // if ( (wantedDot.getWidth() != 0)
1240  // && (wantedDot.getHeight() != 0)
1241  // && (wantedDot.getArea() != 0) )
1242  if ((std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon()) &&
1243  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon()) &&
1244  (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon()))
1245  // if (size_precision!=0){
1246  {
1247  if (std::fabs(size_precision) > std::numeric_limits<double>::epsilon()) {
1248  double epsilon = 0.001;
1249 #ifdef DEBUG
1250  std::cout << "test size precision......................\n";
1251  std::cout << "wanted dot: "
1252  << "w=" << wantedDot.getWidth() << " h=" << wantedDot.getHeight() << " s=" << wantedDot.getArea()
1253  << " precision=" << size_precision << " epsilon=" << epsilon << std::endl;
1254  std::cout << "dot found: "
1255  << "w=" << getWidth() << " h=" << getHeight() << " s=" << getArea() << std::endl;
1256 #endif
1257 
1258  if ((wantedDot.getWidth() * size_precision - epsilon < getWidth()) == false) {
1259  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1260 #ifdef DEBUG
1261  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1262 #endif
1263  return false;
1264  }
1265 
1266  if ((getWidth() < wantedDot.getWidth() / (size_precision + epsilon)) == false) {
1267  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1268 #ifdef DEBUG
1269  printf("Bad width %g > %g for dot (%g, %g)\n", getWidth(), wantedDot.getWidth() / (size_precision + epsilon),
1270  cog.get_u(), cog.get_v());
1271 #endif
1272  return false;
1273  }
1274 
1275  if ((wantedDot.getHeight() * size_precision - epsilon < getHeight()) == false) {
1276  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1277 #ifdef DEBUG
1278  printf("Bad height %g > %g for dot (%g, %g)\n", wantedDot.getHeight() * size_precision - epsilon, getHeight(),
1279  cog.get_u(), cog.get_v());
1280 #endif
1281  return false;
1282  }
1283 
1284  if ((getHeight() < wantedDot.getHeight() / (size_precision + epsilon)) == false) {
1285  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1286 #ifdef DEBUG
1287  printf("Bad height %g > %g for dot (%g, %g)\n", getHeight(), wantedDot.getHeight() / (size_precision + epsilon),
1288  cog.get_u(), cog.get_v());
1289 #endif
1290  return false;
1291  }
1292 
1293  if ((wantedDot.getArea() * (size_precision * size_precision) - epsilon < getArea()) == false) {
1294  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1295 #ifdef DEBUG
1296  printf("Bad surface %g > %g for dot (%g, %g)\n",
1297  wantedDot.getArea() * (size_precision * size_precision) - epsilon, getArea(), cog.get_u(), cog.get_v());
1298 #endif
1299  return false;
1300  }
1301 
1302  if ((getArea() < wantedDot.getArea() / (size_precision * size_precision + epsilon)) == false) {
1303  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1304 #ifdef DEBUG
1305  printf("Bad surface %g < %g for dot (%g, %g)\n", getArea(),
1306  wantedDot.getArea() / (size_precision * size_precision + epsilon), cog.get_u(), cog.get_v());
1307 #endif
1308  return false;
1309  }
1310  }
1311  }
1312  //
1313  // Now we can proceed to more advanced (and costy) checks.
1314  // First check there is a white (>level) elipse within dot
1315  // Then check the dot is surrounded by a black ellipse.
1316  //
1317  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1318  int nb_bad_points = 0;
1319  int nb_max_bad_points = (int)(nb_point_to_test * allowedBadPointsPercentage_);
1320  double step_angle = 2 * M_PI / nb_point_to_test;
1321 
1322  // if (ellipsoidShape_precision != 0 && compute_moment) {
1323  if (std::fabs(ellipsoidShape_precision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1324  // std::cout << "test shape precision......................\n";
1325  // See F. Chaumette. Image moments: a general and useful set of features
1326  // for visual servoing. IEEE Trans. on Robotics, 20(4):713-723, August
1327  // 2004.
1328 
1329  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1330  // = m11 - m10 * m01 / m00
1331  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1332  // = m20 - m10^2 / m00
1333  // mu02 = m02 - m01^2 / m00
1334  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1335  //
1336  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1337  //
1338  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1339 
1340  // we compute parameters of the estimated ellipse
1341  double tmp1 = (m01 * m01 - m10 * m10) / m00 + (m20 - m02);
1342  double tmp2 = m11 - m10 * m01 / m00;
1343  double Sqrt = sqrt(tmp1 * tmp1 + 4 * tmp2 * tmp2);
1344  double a1 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 + Sqrt));
1345  double a2 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 - Sqrt));
1346  double alpha = 0.5 * atan2(2 * (m11 * m00 - m10 * m01), ((m20 - m02) * m00 - m10 * m10 + m01 * m01));
1347 
1348  // to be able to track small dots, minorize the ellipsoid radius for the
1349  // inner test
1350  a1 -= 1.0;
1351  a2 -= 1.0;
1352 
1353  double innerCoef = ellipsoidShape_precision;
1354  unsigned int u, v;
1355  double cog_u = this->cog.get_u();
1356  double cog_v = this->cog.get_v();
1357 
1358  vpImagePoint ip;
1359  nb_bad_points = 0;
1360  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1361  u = (unsigned int)(cog_u + innerCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1362  v = (unsigned int)(cog_v + innerCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1363  if (!this->hasGoodLevel(I, u, v)) {
1364 // vpTRACE("Inner circle pixel (%d, %d) has bad level for dot (%g, %g)",
1365 // u, v, cog_u, cog_v);
1366 #ifdef DEBUG
1367  printf("Inner circle pixel (%u, %u) has bad level for dot (%g, %g): "
1368  "%d not in [%u, %u]\n",
1369  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1370 #endif
1371  // return false;
1372  nb_bad_points++;
1373  }
1374  if (graphics) {
1375  for (unsigned int t = 0; t < thickness; t++) {
1376  ip.set_u(u + t);
1377  ip.set_v(v);
1379  }
1380  }
1381 #ifdef DEBUG
1383  vpDisplay::flush(I);
1384 #endif
1385  }
1386  if (nb_bad_points > nb_max_bad_points) {
1387 #ifdef DEBUG
1388  printf("Inner ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1389 #endif
1390  return false;
1391  }
1392  // to be able to track small dots, maximize the ellipsoid radius for the
1393  // inner test
1394  a1 += 2.0;
1395  a2 += 2.0;
1396 
1397  double outCoef = 2 - ellipsoidShape_precision; // 1.6;
1398  nb_bad_points = 0;
1399  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1400  u = (unsigned int)(cog_u + outCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1401  v = (unsigned int)(cog_v + outCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1402 #ifdef DEBUG
1403  // vpDisplay::displayRectangle(I, area, vpColor::yellow);
1404  vpDisplay::displayCross(I, (int)v, (int)u, 7, vpColor::purple);
1405  vpDisplay::flush(I);
1406 #endif
1407  // If outside the area, continue
1408  if ((double)u < area.getLeft() || (double)u > area.getRight() || (double)v < area.getTop() ||
1409  (double)v > area.getBottom()) {
1410  continue;
1411  }
1412  if (!this->hasReverseLevel(I, u, v)) {
1413 // vpTRACE("Outside circle pixel (%d, %d) has bad level for dot (%g,
1414 // %g)", u, v, cog_u, cog_v);
1415 #ifdef DEBUG
1416  printf("Outside circle pixel (%u, %u) has bad level for dot (%g, "
1417  "%g): %d not in [%u, %u]\n",
1418  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1419 #endif
1420  nb_bad_points++;
1421  // return false;
1422  }
1423  if (graphics) {
1424  for (unsigned int t = 0; t < thickness; t++) {
1425  ip.set_u(u + t);
1426  ip.set_v(v);
1427 
1429  }
1430  }
1431  }
1432  }
1433  if (nb_bad_points > nb_max_bad_points) {
1434 #ifdef DEBUG
1435  printf("Outside ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1436 #endif
1437  return false;
1438  }
1439 
1440  return true;
1441 }
1442 
1461 bool vpDot2::hasGoodLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
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 
1485 bool vpDot2::hasReverseLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1486 {
1487 
1488  if (!isInArea(u, v))
1489  return false;
1490 
1491  if (I[v][u] < gray_level_min || I[v][u] > gray_level_max) {
1492  return true;
1493  } else {
1494  return false;
1495  }
1496 }
1497 
1506 vpDot2 *vpDot2::getInstance() { return new vpDot2(); }
1507 
1523 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const { freeman_chain = direction_list; }
1524 
1525 /******************************************************************************
1526  *
1527  * PRIVATE METHODS
1528  *
1529  ******************************************************************************/
1530 
1562 bool vpDot2::computeParameters(const vpImage<unsigned char> &I, const double &_u, const double &_v)
1563 {
1564  direction_list.clear();
1565  ip_edges_list.clear();
1566 
1567  double est_u = _u; // estimated
1568  double est_v = _v;
1569 
1570  // if u has default value, set it to the actual center value
1571  // if( est_u == -1.0 )
1572  if (std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u), 1.) * std::numeric_limits<double>::epsilon()) {
1573  est_u = this->cog.get_u();
1574  }
1575 
1576  // if v has default value, set it to the actual center value
1577  // if( est_v == -1.0 )
1578  if (std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v), 1.) * std::numeric_limits<double>::epsilon()) {
1579  est_v = this->cog.get_v();
1580  }
1581 
1582  // if the estimated position of the dot is out of the image, not need to
1583  // continue, return an error tracking
1584  if (!isInArea((unsigned int)est_u, (unsigned int)est_v)) {
1585  vpDEBUG_TRACE(3,
1586  "Initial pixel coordinates (%d, %d) for dot tracking are "
1587  "not in the area",
1588  (int)est_u, (int)est_v);
1589  return false;
1590  }
1591 
1592  bbox_u_min = (int)I.getWidth();
1593  bbox_u_max = 0;
1594  bbox_v_min = (int)I.getHeight();
1595  bbox_v_max = 0;
1596 
1597  // if the first point doesn't have the right level then there's no point to
1598  // continue.
1599  if (!hasGoodLevel(I, (unsigned int)est_u, (unsigned int)est_v)) {
1600  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates", (int)est_u, (int)est_v);
1601  return false;
1602  }
1603 
1604  // find the border
1605 
1606  if (!findFirstBorder(I, (unsigned int)est_u, (unsigned int)est_v, this->firstBorder_u, this->firstBorder_v)) {
1607 
1608  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates", (int)est_u, (int)est_v);
1609  return false;
1610  }
1611 
1612  unsigned int dir = 6;
1613 
1614  // Determine the first element of the Freeman chain
1615  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
1616  unsigned int firstDir = dir;
1617 
1618  // if we are now out of the image, return an error tracking
1619  if (!isInArea(this->firstBorder_u, this->firstBorder_v)) {
1620  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area", this->firstBorder_u,
1621  this->firstBorder_v);
1622  return false;
1623  }
1624 
1625  // store the new direction and dot border coordinates.
1626  direction_list.push_back(dir);
1627  vpImagePoint ip;
1628  ip.set_u(this->firstBorder_u);
1629  ip.set_v(this->firstBorder_v);
1630 
1631  ip_edges_list.push_back(ip);
1632 
1633  int border_u = (int)this->firstBorder_u;
1634  int border_v = (int)this->firstBorder_v;
1635 
1636  // vpTRACE("-----------------------------------------");
1637  // vpTRACE("first border_u: %d border_v: %d dir: %d",
1638  // this->firstBorder_u, this->firstBorder_v,firstDir);
1639  int du, dv;
1640  float dS, dMu, dMv, dMuv, dMu2, dMv2;
1641  m00 = 0.0;
1642  m10 = 0.0;
1643  m01 = 0.0;
1644  m11 = 0.0;
1645  m20 = 0.0;
1646  m02 = 0.0;
1647  // while we didn't come back to the first point, follow the border
1648  do {
1649  // if it was asked, show the border
1650  if (graphics) {
1651  for (int t = 0; t < (int)thickness; t++) {
1652  ip.set_u(border_u + t);
1653  ip.set_v(border_v);
1654 
1656  }
1657  // vpDisplay::flush(I);
1658  }
1659 #ifdef DEBUG
1660  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1661  vpDisplay::flush(I);
1662 #endif
1663  // Determine the increments for the parameters
1664  computeFreemanParameters(border_u, border_v, dir, du, dv,
1665  dS, // surface
1666  dMu, dMv, // first order moments
1667  dMuv, dMu2, dMv2); // second order moment
1668 
1669  // Update the parameters
1670  border_u += du; // Next position on the border
1671  border_v += dv;
1672  m00 += dS; // enclosed area
1673  m10 += dMu; // First order moment along v axis
1674  m01 += dMv; // First order moment along u axis
1675  if (compute_moment) {
1676  m11 += dMuv; // Second order moment
1677  m20 += dMu2; // Second order moment along v axis
1678  m02 += dMv2; // Second order moment along u axis
1679  }
1680  // if we are now out of the image, return an error tracking
1681  if (!isInArea((unsigned int)border_u, (unsigned int)border_v)) {
1682 
1683  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
1684  // Can Occur on a single pixel dot located on the top border
1685  return false;
1686  }
1687 
1688  // store the new direction and dot border coordinates.
1689 
1690  direction_list.push_back(dir);
1691 
1692  ip.set_u(border_u);
1693  ip.set_v(border_v);
1694  ip_edges_list.push_back(ip);
1695 
1696  // vpDisplay::getClick(I);
1697 
1698  // update the extreme point of the dot.
1699  if (border_v < bbox_v_min)
1700  bbox_v_min = border_v;
1701  if (border_v > bbox_v_max)
1702  bbox_v_max = border_v;
1703  if (border_u < bbox_u_min)
1704  bbox_u_min = border_u;
1705  if (border_u > bbox_u_max)
1706  bbox_u_max = border_u;
1707 
1708  // move around the tracked entity by following the border.
1709  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
1710  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)", border_u, border_v);
1711  return false;
1712  }
1713 
1714  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v,
1715  // dir);
1716 
1717  } while ((getFirstBorder_u() != (unsigned int)border_u || getFirstBorder_v() != (unsigned int)border_v ||
1718  firstDir != dir) &&
1719  isInArea((unsigned int)border_u, (unsigned int)border_v));
1720 
1721 #ifdef VP_DEBUG
1722 #if VP_DEBUG_MODE == 3
1723  vpDisplay::flush(I);
1724 #endif
1725 #endif
1726 
1727  // if the surface is one or zero , the center of gravity wasn't properly
1728  // detected. Return an error tracking.
1729  // if( m00 == 0 || m00 == 1 )
1730  if (std::fabs(m00) <= std::numeric_limits<double>::epsilon() ||
1731  std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.) * std::numeric_limits<double>::epsilon()) {
1732  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
1733  return false;
1734  } else // compute the center
1735  {
1736  // this magic formula gives the coordinates of the center of gravity
1737  double tmpCenter_u = m10 / m00;
1738  double tmpCenter_v = m01 / m00;
1739 
1740  // Updates the central moments
1741  if (compute_moment) {
1742  mu11 = m11 - tmpCenter_u * m01;
1743  mu02 = m02 - tmpCenter_v * m01;
1744  mu20 = m20 - tmpCenter_u * m10;
1745  }
1746 
1747  // check the center is in the image... never know...
1748  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
1749  // (unsigned int)tmpCenter_v ) )
1750  // {
1751  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has
1752  // not a good in level", tmpCenter_u, tmpCenter_v); return false;
1753  // }
1754 
1755  cog.set_u(tmpCenter_u);
1756  cog.set_v(tmpCenter_v);
1757  }
1758 
1759  width = bbox_u_max - bbox_u_min + 1;
1760  height = bbox_v_max - bbox_v_min + 1;
1761  surface = m00;
1762 
1763  computeMeanGrayLevel(I);
1764  return true;
1765 }
1766 
1782 bool vpDot2::findFirstBorder(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1783  unsigned int &border_u, unsigned int &border_v)
1784 {
1785  // find the border
1786 
1787  // NOTE:
1788  // from here we use int and not double. This is because we don't have
1789  // rounding problems and it's actually more a trouble than smth else to
1790  // work with double when navigating around the dot.
1791  border_u = u;
1792  border_v = v;
1793  double epsilon = 0.001;
1794 
1795 #ifdef DEBUG
1796  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
1797 #endif
1798  while (hasGoodLevel(I, border_u + 1, border_v) && border_u < area.getRight() /*I.getWidth()*/) {
1799  // if the width of this dot was initialised and we already crossed the dot
1800  // on more than the max possible width, no need to continue, return an
1801  // error tracking
1802  if (getWidth() > 0 && (border_u - u) > getWidth() / (getMaxSizeSearchDistancePrecision() + epsilon)) {
1803  vpDEBUG_TRACE(3,
1804  "The found dot (%d, %d, %d) has a greater width than the "
1805  "required one",
1806  u, v, border_u);
1807  return false;
1808  }
1809 #ifdef DEBUG
1810  vpDisplay::displayPoint(I, (int)border_v, (int)border_u + 1, vpColor::green);
1811  vpDisplay::flush(I);
1812 #endif
1813 
1814  border_u++;
1815  }
1816  return true;
1817 }
1818 
1837 bool vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1838  unsigned int &element)
1839 {
1840 
1841  if (hasGoodLevel(I, u, v)) {
1842  unsigned int _u = u;
1843  unsigned int _v = v;
1844  // get the point on the right of the point passed in
1845  updateFreemanPosition(_u, _v, (element + 2) % 8);
1846  if (hasGoodLevel(I, _u, _v)) {
1847  element = (element + 2) % 8; // turn right
1848  } else {
1849  unsigned int _u1 = u;
1850  unsigned int _v1 = v;
1851  updateFreemanPosition(_u1, _v1, (element + 1) % 8);
1852 
1853  if (hasGoodLevel(I, _u1, _v1)) {
1854  element = (element + 1) % 8; // turn diag right
1855  } else {
1856  unsigned int _u2 = u;
1857  unsigned int _v2 = v;
1858  updateFreemanPosition(_u2, _v2, element); // same direction
1859 
1860  if (hasGoodLevel(I, _u2, _v2)) {
1861  // element = element; // keep same dir
1862  } else {
1863  unsigned int _u3 = u;
1864  unsigned int _v3 = v;
1865  updateFreemanPosition(_u3, _v3, (element + 7) % 8); // diag left
1866 
1867  if (hasGoodLevel(I, _u3, _v3)) {
1868  element = (element + 7) % 8; // turn diag left
1869  } else {
1870  unsigned int _u4 = u;
1871  unsigned int _v4 = v;
1872  updateFreemanPosition(_u4, _v4, (element + 6) % 8); // left
1873 
1874  if (hasGoodLevel(I, _u4, _v4)) {
1875  element = (element + 6) % 8; // turn left
1876  } else {
1877  unsigned int _u5 = u;
1878  unsigned int _v5 = v;
1879  updateFreemanPosition(_u5, _v5, (element + 5) % 8); // left
1880 
1881  if (hasGoodLevel(I, _u5, _v5)) {
1882  element = (element + 5) % 8; // turn diag down
1883  } else {
1884  unsigned int _u6 = u;
1885  unsigned int _v6 = v;
1886  updateFreemanPosition(_u6, _v6, (element + 4) % 8); // left
1887 
1888  if (hasGoodLevel(I, _u6, _v6)) {
1889  element = (element + 4) % 8; // turn down
1890  } else {
1891  unsigned int _u7 = u;
1892  unsigned int _v7 = v;
1893  updateFreemanPosition(_u7, _v7, (element + 3) % 8); // diag
1894 
1895  if (hasGoodLevel(I, _u7, _v7)) {
1896  element = (element + 3) % 8; // turn diag right down
1897  } else {
1898  // No neighbor with a good level
1899  //
1900  return false;
1901  }
1902  }
1903  }
1904  }
1905  }
1906  }
1907  }
1908  }
1909  }
1910 
1911  else {
1912  return false;
1913  }
1914 
1915  return true;
1916 }
1917 
1949 void vpDot2::computeFreemanParameters(const int &u_p, const int &v_p, unsigned int &element, int &du, int &dv,
1950  float &dS, float &dMu, float &dMv, float &dMuv, float &dMu2, float &dMv2)
1951 {
1952  du = 0;
1953  dv = 0;
1954  dMuv = 0;
1955  dMu2 = 0;
1956  dMv2 = 0;
1957 
1958  /*
1959  3 2 1
1960  \ | /
1961  \|/
1962  4 ------- 0
1963  /|\
1964  / | \
1965  5 6 7
1966  */
1967  switch (element) {
1968  case 0: // go right
1969  du = 1;
1970  dS = (float)v_p;
1971  dMu = 0.0;
1972  dMv = (float)(0.5 * v_p * v_p);
1973  if (compute_moment) {
1974  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
1975  dMu2 = 0;
1976  dMv2 = (float)(1.0 / 3. * v_p * v_p * v_p);
1977  }
1978  break;
1979 
1980  case 1: // go right top
1981  du = 1;
1982  dv = 1;
1983  dS = (float)(v_p + 0.5);
1984  dMu = -(float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
1985  dMv = (float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
1986  if (compute_moment) {
1987  float half_u_p = (float)(0.5 * u_p);
1988  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) + v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
1989  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1. / 12.0);
1990  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1. / 12.0);
1991  }
1992  break;
1993 
1994  case 2: // go top
1995  dv = 1;
1996  dS = 0.0;
1997  dMu = (float)(-0.5 * u_p * u_p);
1998  dMv = 0.0;
1999  if (compute_moment) {
2000  dMuv = 0;
2001  dMu2 = (float)(-1.0 / 3. * u_p * u_p * u_p);
2002  dMv2 = 0;
2003  }
2004  break;
2005 
2006  case 3:
2007  du = -1;
2008  dv = 1;
2009  dS = (float)(-v_p - 0.5);
2010  dMu = -(float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2011  dMv = -(float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
2012  if (compute_moment) {
2013  float half_u_p = (float)(0.5 * u_p);
2014  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) + v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2015  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2016  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1. / 12.0);
2017  }
2018  break;
2019 
2020  case 4:
2021  du = -1;
2022  dS = (float)(-v_p);
2023  dMv = (float)(-0.5 * v_p * v_p);
2024  dMu = 0.0;
2025  if (compute_moment) {
2026  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2027  dMu2 = 0;
2028  dMv2 = (float)(-1.0 / 3. * v_p * v_p * v_p);
2029  }
2030  break;
2031 
2032  case 5:
2033  du = -1;
2034  dv = -1;
2035  dS = (float)(-v_p + 0.5);
2036  dMu = (float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2037  dMv = (float)(-(0.5 * v_p * (v_p - 1) + 1.0 / 6.0));
2038  if (compute_moment) {
2039  float half_u_p = (float)(0.5 * u_p);
2040  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) - v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2041  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2042  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2043  }
2044  break;
2045 
2046  case 6:
2047  dv = -1;
2048  dS = 0.0;
2049  dMu = (float)(0.5 * u_p * u_p);
2050  dMv = 0.0;
2051  if (compute_moment) {
2052  dMuv = 0;
2053  dMu2 = (float)(1.0 / 3. * u_p * u_p * u_p);
2054  dMv2 = 0;
2055  }
2056  break;
2057 
2058  case 7:
2059  du = 1;
2060  dv = -1;
2061  dS = (float)(v_p - 0.5);
2062  dMu = (float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
2063  dMv = (float)(0.5 * v_p * (v_p - 1) + 1.0 / 6.0);
2064  if (compute_moment) {
2065  float half_u_p = (float)(0.5 * u_p);
2066  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) - v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
2067  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1. / 12.0);
2068  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2069  }
2070  break;
2071  }
2072 }
2073 
2087 void vpDot2::updateFreemanPosition(unsigned int &u, unsigned int &v, const unsigned int &dir)
2088 {
2089  switch (dir) {
2090  case 0:
2091  u += 1;
2092  break;
2093  case 1:
2094  u += 1;
2095  v += 1;
2096  break;
2097  case 2:
2098  v += 1;
2099  break;
2100  case 3:
2101  u -= 1;
2102  v += 1;
2103  break;
2104  case 4:
2105  u -= 1;
2106  break;
2107  case 5:
2108  u -= 1;
2109  v -= 1;
2110  break;
2111  case 6:
2112  v -= 1;
2113  break;
2114  case 7:
2115  u += 1;
2116  v -= 1;
2117  break;
2118  }
2119 }
2120 
2132 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const { return isInImage(I, cog); }
2133 
2145 bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
2146 {
2147  unsigned int h = I.getHeight();
2148  unsigned int w = I.getWidth();
2149  double u = ip.get_u();
2150  double v = ip.get_v();
2151 
2152  if (u < 0 || u >= w)
2153  return false;
2154  if (v < 0 || v >= h)
2155  return false;
2156  return true;
2157 }
2158 
2170 bool vpDot2::isInArea(const unsigned int &u, const unsigned int &v) const
2171 {
2172  unsigned int area_u_min = (unsigned int)area.getLeft();
2173  unsigned int area_u_max = (unsigned int)area.getRight();
2174  unsigned int area_v_min = (unsigned int)area.getTop();
2175  unsigned int area_v_max = (unsigned int)area.getBottom();
2176 
2177  if (u < area_u_min || u > area_u_max)
2178  return false;
2179  if (v < area_v_min || v > area_v_max)
2180  return false;
2181  return true;
2182 }
2183 
2195 void vpDot2::getGridSize(unsigned int &gridWidth, unsigned int &gridHeight)
2196 {
2197  // first get the research grid width and height Note that
2198  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2199  // contained in the dot. We gent this here if the dot is a perfect disc.
2200  // More accurate criterium to define the grid should be implemented if
2201  // necessary
2202  gridWidth = (unsigned int)(getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2203  gridHeight = (unsigned int)(getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2204 
2205  if (gridWidth == 0)
2206  gridWidth = 1;
2207  if (gridHeight == 0)
2208  gridHeight = 1;
2209 }
2210 
2223 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char> &I)
2224 {
2225  int cog_u = (int)cog.get_u();
2226  int cog_v = (int)cog.get_v();
2227 
2228  unsigned int sum_value = 0;
2229  unsigned int nb_pixels = 0;
2230 
2231  for (unsigned int i = (unsigned int)this->bbox_u_min; i <= (unsigned int)this->bbox_u_max; i++) {
2232  unsigned int pixel_gray = (unsigned int)I[(unsigned int)cog_v][i];
2233  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2234  sum_value += pixel_gray;
2235  nb_pixels++;
2236  }
2237  }
2238  for (unsigned int i = (unsigned int)this->bbox_v_min; i <= (unsigned int)this->bbox_v_max; i++) {
2239  unsigned char pixel_gray = I[i][(unsigned int)cog_u];
2240  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2241  sum_value += pixel_gray;
2242  nb_pixels++;
2243  }
2244  }
2245  if (nb_pixels < 10) { // could be good to choose the min nb points from area of dot
2246  // add diagonals points to have enough point
2247  int imin, imax;
2248  if ((cog_u - bbox_u_min) > (cog_v - bbox_v_min)) {
2249  imin = cog_v - bbox_v_min;
2250  } else {
2251  imin = cog_u - bbox_u_min;
2252  }
2253  if ((bbox_u_max - cog_u) > (bbox_v_max - cog_v)) {
2254  imax = bbox_v_max - cog_v;
2255  } else {
2256  imax = bbox_u_max - cog_u;
2257  }
2258  for (int i = -imin; i <= imax; i++) {
2259  unsigned int pixel_gray = (unsigned int)I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2260  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2261  sum_value += pixel_gray;
2262  nb_pixels++;
2263  }
2264  }
2265 
2266  if ((cog_u - bbox_u_min) > (bbox_v_max - cog_v)) {
2267  imin = bbox_v_max - cog_v;
2268  } else {
2269  imin = cog_u - bbox_u_min;
2270  }
2271  if ((bbox_u_max - cog_u) > (cog_v - bbox_v_min)) {
2272  imax = cog_v - bbox_v_min;
2273  } else {
2274  imax = bbox_u_max - cog_u;
2275  }
2276 
2277  for (int i = -imin; i <= imax; i++) {
2278  unsigned char pixel_gray = I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2279  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2280  sum_value += pixel_gray;
2281  nb_pixels++;
2282  }
2283  }
2284  }
2285 
2286  if (nb_pixels == 0) {
2287  // should never happen
2288  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No point was found"));
2289  } else {
2290  mean_gray_level = sum_value / nb_pixels;
2291  }
2292 }
2293 
2312 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I,
2313  vpColor col, bool trackDot)
2314 {
2315  vpMatrix Cogs(n, 2);
2316  vpImagePoint cog;
2317  unsigned int i;
2318  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
2319  if (fromFile) {
2320  vpMatrix::loadMatrix(dotFile, Cogs);
2321  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
2322  }
2323 
2324  // test number of cogs in file
2325  if (Cogs.getRows() < n) {
2326  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
2327  fromFile = false;
2328  }
2329 
2330  // read from file and tracks the dots
2331  if (fromFile) {
2332  try {
2333  for (i = 0; i < n; ++i) {
2334  cog.set_uv(Cogs[i][0], Cogs[i][1]);
2335  dot[i].setGraphics(true);
2336  dot[i].setCog(cog);
2337  if (trackDot) {
2338  dot[i].initTracking(I, cog);
2339  dot[i].track(I);
2340  vpDisplay::displayCross(I, cog, 10, col);
2341  }
2342  }
2343  } catch (...) {
2344  std::cout << "Cannot track dots from file" << std::endl;
2345  fromFile = false;
2346  }
2347  vpDisplay::flush(I);
2348 
2349  // check that dots are far away ones from the other
2350  for (i = 0; i < n && fromFile; ++i) {
2351  double d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
2352  for (unsigned int j = 0; j < n && fromFile; ++j)
2353  if (j != i)
2354  if (dot[i].getDistance(dot[j]) < d) {
2355  fromFile = false;
2356  std::cout << "Dots from file seem incoherent" << std::endl;
2357  }
2358  }
2359  }
2360 
2361  if (!fromFile) {
2362  vpDisplay::display(I);
2363  vpDisplay::flush(I);
2364 
2365  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
2366  for (i = 0; i < n; i++) {
2367  if (trackDot) {
2368  dot[i].setGraphics(true);
2369  dot[i].initTracking(I);
2370  cog = dot[i].getCog();
2371  } else {
2372  vpDisplay::getClick(I, cog);
2373  dot[i].setCog(cog);
2374  }
2375  Cogs[i][0] = cog.get_u();
2376  Cogs[i][1] = cog.get_v();
2377  vpDisplay::displayCross(I, cog, 10, col);
2378  vpDisplay::flush(I);
2379  }
2380  }
2381 
2382  if (!fromFile && (dotFile != "")) {
2383  vpMatrix::saveMatrix(dotFile, Cogs);
2384  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
2385  }
2386 
2387  // back to non graphic mode
2388  for (i = 0; i < n; ++i)
2389  dot[i].setGraphics(false);
2390 
2391  return Cogs;
2392 }
2393 
2410 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I,
2411  std::vector<vpImagePoint> &cogs, vpImagePoint *cogStar)
2412 {
2413  unsigned int i;
2414  // tracking
2415  for (i = 0; i < n; ++i) {
2416  dot[i].track(I);
2417  cogs.push_back(dot[i].getCog());
2418  }
2419  // trajectories
2420  for (i = n; i < cogs.size(); ++i)
2421  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::green, true);
2422  // initial position
2423  for (i = 0; i < n; ++i)
2424  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::blue, true);
2425  // if exists, desired position
2426  if (cogStar != NULL)
2427  for (i = 0; i < n; ++i) {
2428  vpDisplay::displayDotLine(I, cogStar[i], dot[i].getCog(), vpColor::red);
2429  vpDisplay::displayCircle(I, cogStar[i], 4, vpColor::red, true);
2430  }
2431  vpDisplay::flush(I);
2432 }
2433 
2449  const std::list<vpImagePoint> &edges_list, vpColor color, unsigned int thickness)
2450 {
2451  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2452  std::list<vpImagePoint>::const_iterator it;
2453 
2454  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2455  vpDisplay::displayPoint(I, *it, color);
2456  }
2457 }
2458 
2473 void vpDot2::display(const vpImage<vpRGBa> &I, const vpImagePoint &cog, const std::list<vpImagePoint> &edges_list,
2474  vpColor color, unsigned int thickness)
2475 {
2476  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2477  std::list<vpImagePoint>::const_iterator it;
2478 
2479  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2480  vpDisplay::displayPoint(I, *it, color);
2481  }
2482 }
2483 
2489 VISP_EXPORT std::ostream &operator<<(std::ostream &os, vpDot2 &d) { return (os << "(" << d.getCog() << ")"); }
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:164
double get_i() const
Definition: vpImagePoint.h:204
double m02
Definition: vpDot2.h:391
double getMeanGrayLevel() const
Definition: vpDot2.h:215
double getTop() const
Definition: vpRect.h:192
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:331
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:979
double getHeight() const
Definition: vpDot2.cpp:630
double mu02
Definition: vpDot2.h:410
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:833
void set_u(double u)
Definition: vpImagePoint.h:226
double getSizePrecision() const
Definition: vpDot2.cpp:651
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1) const
Definition: vpDot2.cpp:212
void set_uv(double u, double v)
Definition: vpImagePoint.h:248
Class to define colors available for display functionnalities.
Definition: vpColor.h:119
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:270
void setGraphics(bool activate)
Definition: vpDot2.h:294
vpDot2 & operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:147
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:241
double getArea() const
Definition: vpDot2.cpp:637
error that can be emited by ViSP classes.
Definition: vpException.h:71
double m11
Definition: vpDot2.h:375
unsigned int getRows() const
Definition: vpArray2D.h:289
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
static bool saveMatrix(const std::string &filename, const vpArray2D< double > &M, bool binary=false, const char *header="")
Definition: vpMatrix.h:727
static const vpColor green
Definition: vpColor.h:182
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:126
double m01
Definition: vpDot2.h:367
static void flush(const vpImage< unsigned char > &I)
double getRight() const
Definition: vpRect.h:179
static const vpColor red
Definition: vpColor.h:179
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:64
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:143
friend VISP_EXPORT std::ostream & operator<<(std::ostream &os, vpDot2 &d)
Definition: vpDot2.cpp:2489
void setGraphicsThickness(unsigned int t)
Definition: vpDot2.h:301
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:735
double get_u() const
Definition: vpImagePoint.h:263
Error that can be emited by the vpTracker class and its derivates.
double mu11
Definition: vpDot2.h:400
double m20
Definition: vpDot2.h:382
#define vpTRACE
Definition: vpDebug.h:416
static double sqr(double x)
Definition: vpMath.h:114
static void display(const vpImage< unsigned char > &I)
double get_j() const
Definition: vpImagePoint.h:215
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:201
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:673
void setArea(const double &area)
Definition: vpDot2.cpp:716
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)
double getLeft() const
Definition: vpRect.h:173
vpDot2()
Definition: vpDot2.cpp:104
void track(const vpImage< unsigned char > &I, bool canMakeTheWindowGrow=true)
Definition: vpDot2.cpp:441
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:806
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:644
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:314
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:207
static void displayCircle(const vpImage< unsigned char > &I, const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1)
void setWidth(const double &width)
Definition: vpDot2.cpp:692
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:2410
void set_v(double v)
Definition: vpImagePoint.h:237
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:763
unsigned int getHeight() const
Definition: vpImage.h:186
void getFreemanChain(std::list< unsigned int > &freeman_chain) const
Definition: vpDot2.cpp:1523
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:668
double getWidth() const
Definition: vpDot2.cpp:623
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:253
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:660
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:730
void setHeight(const double &height)
Definition: vpDot2.cpp:704
double m10
Definition: vpDot2.h:359
#define vpDEBUG_TRACE
Definition: vpDebug.h:487
vpImagePoint getCog() const
Definition: vpDot2.h:161
double mu20
Definition: vpDot2.h:405
void setComputeMoments(bool activate)
Definition: vpDot2.h:256
Defines a rectangle in the plane.
Definition: vpRect.h:78
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
double m00
Definition: vpDot2.h:351
static const vpColor purple
Definition: vpColor.h:190
void setRect(double l, double t, double w, double h)
Definition: vpRect.h:301
unsigned int getWidth() const
Definition: vpImage.h:244
double getBottom() const
Definition: vpRect.h:97
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:2312
static bool loadMatrix(const std::string &filename, vpArray2D< double > &M, bool binary=false, char *header=NULL)
Definition: vpMatrix.h:692
static void displayDotLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
double get_v() const
Definition: vpImagePoint.h:274
virtual ~vpDot2()
Definition: vpDot2.cpp:198
static const vpColor blue
Definition: vpColor.h:185