Visual Servoing Platform  version 3.1.0
vpDot2.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or 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 (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 (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 (vpException &e) {
396  // vpERROR_TRACE("Error caught") ;
397  throw(e);
398  }
399 }
400 
440 {
441  m00 = m11 = m02 = m20 = m10 = m01 = 0;
442 
443  // First, we will estimate the position of the tracked point
444 
445  // Set the search area to the entire image
446  setArea(I);
447 
448  // create a copy of the dot to search
449  // This copy can be saw as the previous dot used to check if the current one
450  // found with computeParameters() is similar to the previous one (see
451  // isValid() function). If the found dot is not similar (or valid), we use
452  // this copy to set the current found dot to the previous one (see below).
453  vpDot2 wantedDot(*this);
454 
455  // vpDEBUG_TRACE(0, "Previous dot: ");
456  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
457  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
458  bool found = computeParameters(I, cog.get_u(), cog.get_v());
459 
460  if (found) {
461  // test if the found dot is valid (ie similar to the previous one)
462  found = isValid(I, wantedDot);
463  if (!found) {
464  *this = wantedDot;
465  // std::cout << "The found dot is not valid" << std::endl;
466  }
467  }
468 
469  if (!found) {
470  // vpDEBUG_TRACE(0, "Search the dot in a biggest window around the
471  // last position"); vpDEBUG_TRACE(0, "Bad computed dot: ");
472  // vpDEBUG_TRACE(0, "u: %f v: %f", get_u(), get_v());
473  // vpDEBUG_TRACE(0, "w: %f h: %f", getWidth(), getHeight());
474 
475  // if estimation was wrong (get an error tracking), look for the dot
476  // closest from the estimation,
477  // i.e. search for dots in an a region of interest around the this dot and
478  // get the first element in the area.
479 
480  // first get the size of the search window from the dot size
481  double searchWindowWidth, searchWindowHeight;
482  // if( getWidth() == 0 || getHeight() == 0 )
483  if (std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon() ||
484  std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon()) {
485  searchWindowWidth = 80.;
486  searchWindowHeight = 80.;
487  } else {
488  searchWindowWidth = getWidth() * 5;
489  searchWindowHeight = getHeight() * 5;
490  }
491  std::list<vpDot2> candidates;
492  searchDotsInArea(I, (int)(this->cog.get_u() - searchWindowWidth / 2.0),
493  (int)(this->cog.get_v() - searchWindowHeight / 2.0), (unsigned int)searchWindowWidth,
494  (unsigned int)searchWindowHeight, candidates);
495 
496  // if the vector is empty, that mean we didn't find any candidate
497  // in the area, return an error tracking.
498  if (candidates.empty()) {
499  // vpERROR_TRACE("No dot was found") ;
501  }
502 
503  // otherwise we've got our dot, update this dot's parameters
504  vpDot2 movingDot = candidates.front();
505 
506  setCog(movingDot.getCog());
507  setArea(movingDot.getArea());
508  setWidth(movingDot.getWidth());
509  setHeight(movingDot.getHeight());
510 
511  // Update the moments
512  m00 = movingDot.m00;
513  m01 = movingDot.m01;
514  m10 = movingDot.m10;
515  m11 = movingDot.m11;
516  m20 = movingDot.m20;
517  m02 = movingDot.m02;
518 
519  // Update the bounding box
520  bbox_u_min = movingDot.bbox_u_min;
521  bbox_u_max = movingDot.bbox_u_max;
522  bbox_v_min = movingDot.bbox_v_min;
523  bbox_v_max = movingDot.bbox_v_max;
524  }
525  // else {
526  // // test if the found dot is valid,
527  // if( ! isValid( I, wantedDot ) ) {
528  // *this = wantedDot;
529  // vpERROR_TRACE("The found dot is invalid:",
530  // "- could be a problem of size (width or height) or "
531  // " surface (number of pixels) which differ too much "
532  // " to the previous one "
533  // "- or a problem of the shape which is not ellipsoid if "
534  // " use setEllipsoidShapePrecision(double
535  // ellipsoidShapePrecision) "
536  // " which is the default case. "
537  // " To track a non ellipsoid shape use
538  // setEllipsoidShapePrecision(0)") ;
539  // throw(vpTrackingException(vpTrackingException::featureLostError,
540  // "The found dot is invalid")) ;
541  // }
542  // }
543 
544  // if this dot is partially out of the image, return an error tracking.
545  if (!isInImage(I)) {
546  // vpERROR_TRACE("The center of gravity of the dot is not in the image") ;
548  "The center of gravity of the dot is not in the image"));
549  }
550 
551  // Get dots center of gravity
552  // unsigned int u = (unsigned int) this->cog.get_u();
553  // unsigned int v = (unsigned int) this->cog.get_v();
554  // Updates the min and max gray levels for the next iteration
555  // double Ip = pow((double)I[v][u]/255,1/gamma);
556  double Ip = pow(getMeanGrayLevel() / 255, 1 / gamma);
557  // printf("current value of gray level center : %i\n", I[v][u]);
558 
559  // getMeanGrayLevel(I);
560  if (Ip - (1 - grayLevelPrecision) < 0) {
561  gray_level_min = 0;
562  } else {
563  gray_level_min = (unsigned int)(255 * pow(Ip - (1 - grayLevelPrecision), gamma));
564  if (gray_level_min > 255)
565  gray_level_min = 255;
566  }
567  gray_level_max = (unsigned int)(255 * pow(Ip + (1 - grayLevelPrecision), gamma));
568  if (gray_level_max > 255)
569  gray_level_max = 255;
570 
571  // printf("%i %i \n",gray_level_max,gray_level_min);
572  if (graphics) {
573  // display a red cross at the center of gravity's location in the image.
574 
575  vpDisplay::displayCross(I, this->cog, 3 * thickness + 8, vpColor::red, thickness);
576  // vpDisplay::flush(I);
577  }
578 }
579 
599 {
600  track(I);
601 
602  ip = this->cog;
603 }
604 
607 
613 double vpDot2::getWidth() const { return width; }
614 
620 double vpDot2::getHeight() const { return height; }
621 
627 double vpDot2::getArea() const { return fabs(surface); }
628 
634 double vpDot2::getGrayLevelPrecision() const { return grayLevelPrecision; }
635 
641 double vpDot2::getSizePrecision() const { return sizePrecision; }
642 
650 double vpDot2::getEllipsoidShapePrecision() const { return ellipsoidShapePrecision; }
651 
658 double vpDot2::getMaxSizeSearchDistancePrecision() const { return maxSizeSearchDistancePrecision; }
659 
663 double vpDot2::getDistance(const vpDot2 &distantDot) const
664 {
665  vpImagePoint cogDistantDot = distantDot.getCog();
666  double diff_u = this->cog.get_u() - cogDistantDot.get_u();
667  double diff_v = this->cog.get_v() - cogDistantDot.get_v();
668  return sqrt(diff_u * diff_u + diff_v * diff_v);
669 }
670 
672 
682 void vpDot2::setWidth(const double &w) { this->width = w; }
683 
694 void vpDot2::setHeight(const double &h) { this->height = h; }
695 
706 void vpDot2::setArea(const double &a) { this->surface = a; }
707 
725 void vpDot2::setGrayLevelPrecision(const double &precision)
726 {
727  double epsilon = 0.05;
728  if (grayLevelPrecision < epsilon) {
729  this->grayLevelPrecision = epsilon;
730  } else if (grayLevelPrecision > 1) {
731  this->grayLevelPrecision = 1.0;
732  } else {
733  this->grayLevelPrecision = precision;
734  }
735 }
753 void vpDot2::setSizePrecision(const double &precision)
754 {
755  if (sizePrecision < 0) {
756  this->sizePrecision = 0;
757  } else if (sizePrecision > 1) {
758  this->sizePrecision = 1.0;
759  } else {
760  this->sizePrecision = precision;
761  }
762 }
763 
796 void vpDot2::setEllipsoidShapePrecision(const double &precision)
797 {
798 
799  if (ellipsoidShapePrecision < 0) {
800  this->ellipsoidShapePrecision = 0;
801  } else if (ellipsoidShapePrecision > 1) {
802  this->ellipsoidShapePrecision = 1.0;
803  } else {
804  this->ellipsoidShapePrecision = precision;
805  }
806 }
807 
823 void vpDot2::setMaxSizeSearchDistancePrecision(const double &precision)
824 {
825  double epsilon = 0.05;
826  if (maxSizeSearchDistancePrecision < epsilon) {
827  this->maxSizeSearchDistancePrecision = epsilon;
828  } else if (maxSizeSearchDistancePrecision > 1) {
829  this->maxSizeSearchDistancePrecision = 1.0;
830  } else {
831  this->maxSizeSearchDistancePrecision = precision;
832  }
833 }
834 
843 void vpDot2::setArea(const vpImage<unsigned char> &I) { setArea(I, 0, 0, I.getWidth(), I.getHeight()); }
844 
857 void vpDot2::setArea(const vpImage<unsigned char> &I, int u, int v, unsigned int w, unsigned int h)
858 {
859  unsigned int image_w = I.getWidth();
860  unsigned int image_h = I.getHeight();
861 
862  // Bounds the area to the image
863  if (u < 0)
864  u = 0;
865  else if (u >= (int)image_w)
866  u = (int)image_w - 1;
867  if (v < 0)
868  v = 0;
869  else if (v >= (int)image_h)
870  v = (int)image_h - 1;
871 
872  if (((unsigned int)u + w) > image_w)
873  w = image_w - (unsigned int)u - 1;
874  if (((unsigned int)v + h) > image_h)
875  h = image_h - (unsigned int)v - 1;
876 
877  area.setRect(u, v, w, h);
878 }
879 
887 void vpDot2::setArea(const vpRect &a) { area = a; }
888 
890 
942 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, std::list<vpDot2> &niceDots)
943 {
944  searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
945 }
946 
969 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, int area_u, int area_v, unsigned int area_w,
970  unsigned int area_h, std::list<vpDot2> &niceDots)
971 
972 {
973  // clear the list of nice dots
974  niceDots.clear();
975 
976  // Fit the input area in the image; we keep only the common part between
977  // this area and the image.
978  setArea(I, area_u, area_v, area_w, area_h);
979 
980  // compute the size of the search grid
981  unsigned int gridWidth;
982  unsigned int gridHeight;
983  getGridSize(gridWidth, gridHeight);
984 
985  if (graphics) {
986  // Display the area were the dot is search
987  vpDisplay::displayRectangle(I, area, vpColor::blue, false, thickness);
988  // vpDisplay::flush(I);
989  }
990 
991 #ifdef DEBUG
993  vpDisplay::flush(I);
994 #endif
995  // start the search loop; for all points of the search grid,
996  // test if the pixel belongs to a valid dot.
997  // if it is so eventually add it to the vector of valid dots.
998  std::list<vpDot2> badDotsVector;
999  std::list<vpDot2>::iterator itnice;
1000  std::list<vpDot2>::iterator itbad;
1001 
1002  vpDot2 *dotToTest = NULL;
1003  vpDot2 tmpDot;
1004 
1005  unsigned int area_u_min = (unsigned int)area.getLeft();
1006  unsigned int area_u_max = (unsigned int)area.getRight();
1007  unsigned int area_v_min = (unsigned int)area.getTop();
1008  unsigned int area_v_max = (unsigned int)area.getBottom();
1009 
1010  unsigned int u, v;
1011  vpImagePoint cogTmpDot;
1012 
1013  for (v = area_v_min; v < area_v_max; v = v + gridHeight) {
1014  for (u = area_u_min; u < area_u_max; u = u + gridWidth) {
1015  // if the pixel we're in doesn't have the right color (outside the
1016  // graylevel interval), no need to check further, just get to the
1017  // next grid intersection.
1018  if (!hasGoodLevel(I, u, v))
1019  continue;
1020 
1021  // Test if an other germ is inside the bounding box of a dot previously
1022  // detected
1023  bool good_germ = true;
1024 
1025  itnice = niceDots.begin();
1026  while (itnice != niceDots.end() && good_germ == true) {
1027  tmpDot = *itnice;
1028 
1029  cogTmpDot = tmpDot.getCog();
1030  double u0 = cogTmpDot.get_u();
1031  double v0 = cogTmpDot.get_v();
1032  double half_w = tmpDot.getWidth() / 2.;
1033  double half_h = tmpDot.getHeight() / 2.;
1034 
1035  if (u >= (u0 - half_w) && u <= (u0 + half_w) && v >= (v0 - half_h) && v <= (v0 + half_h)) {
1036  // Germ is in a previously detected dot
1037  good_germ = false;
1038  }
1039  ++itnice;
1040  }
1041 
1042  if (!good_germ)
1043  continue;
1044 
1045  // Compute the right border position for this possible germ
1046  unsigned int border_u;
1047  unsigned int border_v;
1048  if (findFirstBorder(I, u, v, border_u, border_v) == false) {
1049  // germ is not good.
1050  // Jump all the pixels between v,u and v,
1051  // dotToTest->getFirstBorder_u()
1052  u = border_u;
1053  v = border_v;
1054  continue;
1055  }
1056 
1057  itbad = badDotsVector.begin();
1058 #define vpBAD_DOT_VALUE (*itbad)
1059  vpImagePoint cogBadDot;
1060 
1061  while (itbad != badDotsVector.end() && good_germ == true) {
1062  if ((double)u >= vpBAD_DOT_VALUE.bbox_u_min && (double)u <= vpBAD_DOT_VALUE.bbox_u_max &&
1063  (double)v >= vpBAD_DOT_VALUE.bbox_v_min && (double)v <= vpBAD_DOT_VALUE.bbox_v_max) {
1064  std::list<vpImagePoint>::const_iterator it_edges = ip_edges_list.begin();
1065  while (it_edges != ip_edges_list.end() && good_germ == true) {
1066  // Test if the germ belong to a previously detected dot:
1067  // - from the germ go right to the border and compare this
1068  // position to the list of pixels of previously detected dots
1069  cogBadDot = *it_edges;
1070  // if( border_u == cogBadDot.get_u() && v == cogBadDot.get_v()) {
1071  if ((std::fabs(border_u - cogBadDot.get_u()) <=
1072  vpMath::maximum(std::fabs((double)border_u), std::fabs(cogBadDot.get_u())) *
1073  std::numeric_limits<double>::epsilon()) &&
1074  (std::fabs(v - cogBadDot.get_v()) <=
1075  vpMath::maximum(std::fabs((double)v), std::fabs(cogBadDot.get_v())) *
1076  std::numeric_limits<double>::epsilon())) {
1077  good_germ = false;
1078  }
1079  ++it_edges;
1080  }
1081  }
1082  ++itbad;
1083  }
1084 #undef vpBAD_DOT_VALUE
1085 
1086  if (!good_germ) {
1087  // Jump all the pixels between v,u and v,
1088  // dotToTest->getFirstBorder_u()
1089  u = border_u;
1090  v = border_v;
1091  continue;
1092  }
1093 
1094  vpTRACE(4, "Try germ (%d, %d)", u, v);
1095 
1096  vpImagePoint germ;
1097  germ.set_u(u);
1098  germ.set_v(v);
1099 
1100  // otherwise estimate the width, height and surface of the dot we
1101  // created, and test it.
1102  if (dotToTest != NULL)
1103  delete dotToTest;
1104  dotToTest = getInstance();
1105  dotToTest->setCog(germ);
1106  dotToTest->setGrayLevelMin(getGrayLevelMin());
1107  dotToTest->setGrayLevelMax(getGrayLevelMax());
1109  dotToTest->setSizePrecision(getSizePrecision());
1110  dotToTest->setGraphics(graphics);
1111  dotToTest->setGraphicsThickness(thickness);
1112  dotToTest->setComputeMoments(true);
1113  dotToTest->setArea(area);
1114  dotToTest->setEllipsoidShapePrecision(ellipsoidShapePrecision);
1115  dotToTest->setEllipsoidBadPointsPercentage(allowedBadPointsPercentage_);
1116 
1117  // first compute the parameters of the dot.
1118  // if for some reasons this caused an error tracking
1119  // (dot partially out of the image...), check the next intersection
1120  if (dotToTest->computeParameters(I) == false) {
1121  // Jump all the pixels between v,u and v,
1122  // dotToTest->getFirstBorder_u()
1123  u = border_u;
1124  v = border_v;
1125  continue;
1126  }
1127  // if the dot to test is valid,
1128  if (dotToTest->isValid(I, *this)) {
1129  vpImagePoint cogDotToTest = dotToTest->getCog();
1130  // Compute the distance to the center. The center used here is not the
1131  // area center available by area.getCenter(area_center_u,
1132  // area_center_v) but the center of the input area which may be
1133  // partially outside the image.
1134 
1135  double area_center_u = area_u + area_w / 2.0 - 0.5;
1136  double area_center_v = area_v + area_h / 2.0 - 0.5;
1137 
1138  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
1139  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
1140  double thisDist = sqrt(thisDiff_u * thisDiff_u + thisDiff_v * thisDiff_v);
1141 
1142  bool stopLoop = false;
1143  itnice = niceDots.begin();
1144 
1145  while (itnice != niceDots.end() && stopLoop == false) {
1146  tmpDot = *itnice;
1147 
1148  // double epsilon = 0.001; // detecte +sieurs points
1149  double epsilon = 3.0;
1150  // if the center of the dot is the same than the current
1151  // don't add it, test the next point of the grid
1152  cogTmpDot = tmpDot.getCog();
1153 
1154  if (fabs(cogTmpDot.get_u() - cogDotToTest.get_u()) < epsilon &&
1155  fabs(cogTmpDot.get_v() - cogDotToTest.get_v()) < epsilon) {
1156  stopLoop = true;
1157  // Jump all the pixels between v,u and v,
1158  // tmpDot->getFirstBorder_u()
1159  u = border_u;
1160  v = border_v;
1161  continue;
1162  }
1163 
1164  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
1165  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
1166  double otherDist = sqrt(otherDiff_u * otherDiff_u + otherDiff_v * otherDiff_v);
1167 
1168  // if the distance of the curent vector element to the center
1169  // is greater than the distance of this dot to the center,
1170  // then add this dot before the current vector element.
1171  if (otherDist > thisDist) {
1172  niceDots.insert(itnice, *dotToTest);
1173  ++itnice;
1174  stopLoop = true;
1175  // Jump all the pixels between v,u and v,
1176  // tmpDot->getFirstBorder_u()
1177  u = border_u;
1178  v = border_v;
1179  continue;
1180  }
1181  ++itnice;
1182  }
1183  vpTRACE(4, "End while (%d, %d)", u, v);
1184 
1185  // if we reached the end of the vector without finding the dot
1186  // or inserting it, insert it now.
1187  if (itnice == niceDots.end() && stopLoop == false) {
1188  niceDots.push_back(*dotToTest);
1189  }
1190  } else {
1191  // Store bad dots
1192  badDotsVector.push_front(*dotToTest);
1193  }
1194  }
1195  }
1196  if (dotToTest != NULL)
1197  delete dotToTest;
1198 }
1199 
1220 bool vpDot2::isValid(const vpImage<unsigned char> &I, const vpDot2 &wantedDot)
1221 {
1222  double size_precision = wantedDot.getSizePrecision();
1223  double ellipsoidShape_precision = wantedDot.getEllipsoidShapePrecision();
1224 
1225  //
1226  // First, check the width, height and surface of the dot. Those parameters
1227  // must be the same.
1228  //
1229  // if ( (wantedDot.getWidth() != 0)
1230  // && (wantedDot.getHeight() != 0)
1231  // && (wantedDot.getArea() != 0) )
1232  if ((std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon()) &&
1233  (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon()) &&
1234  (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon()))
1235  // if (size_precision!=0){
1236  {
1237  if (std::fabs(size_precision) > std::numeric_limits<double>::epsilon()) {
1238  double epsilon = 0.001;
1239 #ifdef DEBUG
1240  std::cout << "test size precision......................\n";
1241  std::cout << "wanted dot: "
1242  << "w=" << wantedDot.getWidth() << " h=" << wantedDot.getHeight() << " s=" << wantedDot.getArea()
1243  << " precision=" << size_precision << " epsilon=" << epsilon << std::endl;
1244  std::cout << "dot found: "
1245  << "w=" << getWidth() << " h=" << getHeight() << " s=" << getArea() << std::endl;
1246 #endif
1247 
1248  if ((wantedDot.getWidth() * size_precision - epsilon < getWidth()) == false) {
1249  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1250 #ifdef DEBUG
1251  printf("Bad width > for dot (%g, %g)\n", cog.get_u(), cog.get_v());
1252 #endif
1253  return false;
1254  }
1255 
1256  if ((getWidth() < wantedDot.getWidth() / (size_precision + epsilon)) == false) {
1257  vpDEBUG_TRACE(3, "Bad width > for dot (%g, %g)", cog.get_u(), cog.get_v());
1258 #ifdef DEBUG
1259  printf("Bad width %g > %g for dot (%g, %g)\n", getWidth(), wantedDot.getWidth() / (size_precision + epsilon),
1260  cog.get_u(), cog.get_v());
1261 #endif
1262  return false;
1263  }
1264 
1265  if ((wantedDot.getHeight() * size_precision - epsilon < getHeight()) == false) {
1266  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1267 #ifdef DEBUG
1268  printf("Bad height %g > %g for dot (%g, %g)\n", wantedDot.getHeight() * size_precision - epsilon, getHeight(),
1269  cog.get_u(), cog.get_v());
1270 #endif
1271  return false;
1272  }
1273 
1274  if ((getHeight() < wantedDot.getHeight() / (size_precision + epsilon)) == false) {
1275  vpDEBUG_TRACE(3, "Bad height > for dot (%g, %g)", cog.get_u(), cog.get_v());
1276 #ifdef DEBUG
1277  printf("Bad height %g > %g for dot (%g, %g)\n", getHeight(), wantedDot.getHeight() / (size_precision + epsilon),
1278  cog.get_u(), cog.get_v());
1279 #endif
1280  return false;
1281  }
1282 
1283  if ((wantedDot.getArea() * (size_precision * size_precision) - epsilon < getArea()) == false) {
1284  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1285 #ifdef DEBUG
1286  printf("Bad surface %g > %g for dot (%g, %g)\n",
1287  wantedDot.getArea() * (size_precision * size_precision) - epsilon, getArea(), cog.get_u(), cog.get_v());
1288 #endif
1289  return false;
1290  }
1291 
1292  if ((getArea() < wantedDot.getArea() / (size_precision * size_precision + epsilon)) == false) {
1293  vpDEBUG_TRACE(3, "Bad surface > for dot (%g, %g)", cog.get_u(), cog.get_v());
1294 #ifdef DEBUG
1295  printf("Bad surface %g < %g for dot (%g, %g)\n", getArea(),
1296  wantedDot.getArea() / (size_precision * size_precision + epsilon), cog.get_u(), cog.get_v());
1297 #endif
1298  return false;
1299  }
1300  }
1301  }
1302  //
1303  // Now we can proceed to more advanced (and costy) checks.
1304  // First check there is a white (>level) elipse within dot
1305  // Then check the dot is surrounded by a black ellipse.
1306  //
1307  int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1308  int nb_bad_points = 0;
1309  int nb_max_bad_points = (int)(nb_point_to_test * allowedBadPointsPercentage_);
1310  double step_angle = 2 * M_PI / nb_point_to_test;
1311 
1312  // if (ellipsoidShape_precision != 0 && compute_moment) {
1313  if (std::fabs(ellipsoidShape_precision) > std::numeric_limits<double>::epsilon() && compute_moment) {
1314  // std::cout << "test shape precision......................\n";
1315  // See F. Chaumette. Image moments: a general and useful set of features
1316  // for visual servoing. IEEE Trans. on Robotics, 20(4):713-723, August
1317  // 2004.
1318 
1319  // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1320  // = m11 - m10 * m01 / m00
1321  // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1322  // = m20 - m10^2 / m00
1323  // mu02 = m02 - m01^2 / m00
1324  // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1325  //
1326  // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1327  //
1328  // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1329 
1330  // we compute parameters of the estimated ellipse
1331  double tmp1 = (m01 * m01 - m10 * m10) / m00 + (m20 - m02);
1332  double tmp2 = m11 - m10 * m01 / m00;
1333  double Sqrt = sqrt(tmp1 * tmp1 + 4 * tmp2 * tmp2);
1334  double a1 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 + Sqrt));
1335  double a2 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 - Sqrt));
1336  double alpha = 0.5 * atan2(2 * (m11 * m00 - m10 * m01), ((m20 - m02) * m00 - m10 * m10 + m01 * m01));
1337 
1338  // to be able to track small dots, minorize the ellipsoid radius for the
1339  // inner test
1340  a1 -= 1.0;
1341  a2 -= 1.0;
1342 
1343  double innerCoef = ellipsoidShape_precision;
1344  unsigned int u, v;
1345  double cog_u = this->cog.get_u();
1346  double cog_v = this->cog.get_v();
1347 
1348  vpImagePoint ip;
1349  nb_bad_points = 0;
1350  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1351  u = (unsigned int)(cog_u + innerCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1352  v = (unsigned int)(cog_v + innerCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1353  if (!this->hasGoodLevel(I, u, v)) {
1354 // vpTRACE("Inner cercle pixel (%d, %d) has bad level for dot (%g, %g)",
1355 // u, v, cog_u, cog_v);
1356 #ifdef DEBUG
1357  printf("Inner cercle pixel (%u, %u) has bad level for dot (%g, %g): "
1358  "%d not in [%u, %u]\n",
1359  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1360 #endif
1361  // return false;
1362  nb_bad_points++;
1363  }
1364  if (graphics) {
1365  for (unsigned int t = 0; t < thickness; t++) {
1366  ip.set_u(u + t);
1367  ip.set_v(v);
1369  }
1370  }
1371 #ifdef DEBUG
1373  vpDisplay::flush(I);
1374 #endif
1375  }
1376  if (nb_bad_points > nb_max_bad_points) {
1377 #ifdef DEBUG
1378  printf("Inner ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1379 #endif
1380  return false;
1381  }
1382  // to be able to track small dots, maximize the ellipsoid radius for the
1383  // inner test
1384  a1 += 2.0;
1385  a2 += 2.0;
1386 
1387  double outCoef = 2 - ellipsoidShape_precision; // 1.6;
1388  nb_bad_points = 0;
1389  for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1390  u = (unsigned int)(cog_u + outCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1391  v = (unsigned int)(cog_v + outCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1392 #ifdef DEBUG
1393  // vpDisplay::displayRectangle(I, area, vpColor::yellow);
1394  vpDisplay::displayCross(I, (int)v, (int)u, 7, vpColor::purple);
1395  vpDisplay::flush(I);
1396 #endif
1397  // If outside the area, continue
1398  if ((double)u < area.getLeft() || (double)u > area.getRight() || (double)v < area.getTop() ||
1399  (double)v > area.getBottom()) {
1400  continue;
1401  }
1402  if (!this->hasReverseLevel(I, u, v)) {
1403 // vpTRACE("Outside cercle pixel (%d, %d) has bad level for dot (%g,
1404 // %g)", u, v, cog_u, cog_v);
1405 #ifdef DEBUG
1406  printf("Outside cercle pixel (%u, %u) has bad level for dot (%g, "
1407  "%g): %d not in [%u, %u]\n",
1408  u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1409 #endif
1410  nb_bad_points++;
1411  // return false;
1412  }
1413  if (graphics) {
1414  for (unsigned int t = 0; t < thickness; t++) {
1415  ip.set_u(u + t);
1416  ip.set_v(v);
1417 
1419  }
1420  }
1421  }
1422  }
1423  if (nb_bad_points > nb_max_bad_points) {
1424 #ifdef DEBUG
1425  printf("Outside ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1426 #endif
1427  return false;
1428  }
1429 
1430  return true;
1431 }
1432 
1451 bool vpDot2::hasGoodLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1452 {
1453  if (!isInArea(u, v))
1454  return false;
1455 
1456  if (I[v][u] >= gray_level_min && I[v][u] <= gray_level_max) {
1457  return true;
1458  } else {
1459  return false;
1460  }
1461 }
1462 
1475 bool vpDot2::hasReverseLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1476 {
1477 
1478  if (!isInArea(u, v))
1479  return false;
1480 
1481  if (I[v][u] < gray_level_min || I[v][u] > gray_level_max) {
1482  return true;
1483  } else {
1484  return false;
1485  }
1486 }
1487 
1496 vpDot2 *vpDot2::getInstance() { return new vpDot2(); }
1497 
1513 void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const { freeman_chain = direction_list; }
1514 
1515 /******************************************************************************
1516  *
1517  * PRIVATE METHODS
1518  *
1519  ******************************************************************************/
1520 
1552 bool vpDot2::computeParameters(const vpImage<unsigned char> &I, const double &_u, const double &_v)
1553 {
1554  direction_list.clear();
1555  ip_edges_list.clear();
1556 
1557  double est_u = _u; // estimated
1558  double est_v = _v;
1559 
1560  // if u has default value, set it to the actual center value
1561  // if( est_u == -1.0 )
1562  if (std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u), 1.) * std::numeric_limits<double>::epsilon()) {
1563  est_u = this->cog.get_u();
1564  }
1565 
1566  // if v has default value, set it to the actual center value
1567  // if( est_v == -1.0 )
1568  if (std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v), 1.) * std::numeric_limits<double>::epsilon()) {
1569  est_v = this->cog.get_v();
1570  }
1571 
1572  // if the estimated position of the dot is out of the image, not need to
1573  // continue, return an error tracking
1574  if (!isInArea((unsigned int)est_u, (unsigned int)est_v)) {
1575  vpDEBUG_TRACE(3,
1576  "Initial pixel coordinates (%d, %d) for dot tracking are "
1577  "not in the area",
1578  (int)est_u, (int)est_v);
1579  return false;
1580  }
1581 
1582  bbox_u_min = (int)I.getWidth();
1583  bbox_u_max = 0;
1584  bbox_v_min = (int)I.getHeight();
1585  bbox_v_max = 0;
1586 
1587  // if the first point doesn't have the right level then there's no point to
1588  // continue.
1589  if (!hasGoodLevel(I, (unsigned int)est_u, (unsigned int)est_v)) {
1590  vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates", (int)est_u, (int)est_v);
1591  return false;
1592  }
1593 
1594  // find the border
1595 
1596  if (!findFirstBorder(I, (unsigned int)est_u, (unsigned int)est_v, this->firstBorder_u, this->firstBorder_v)) {
1597 
1598  vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates", (int)est_u, (int)est_v);
1599  return false;
1600  }
1601 
1602  unsigned int dir = 6;
1603 
1604  // Determine the first element of the Freeman chain
1605  computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
1606  unsigned int firstDir = dir;
1607 
1608  // if we are now out of the image, return an error tracking
1609  if (!isInArea(this->firstBorder_u, this->firstBorder_v)) {
1610  vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area", this->firstBorder_u,
1611  this->firstBorder_v);
1612  return false;
1613  }
1614 
1615  // store the new direction and dot border coordinates.
1616  direction_list.push_back(dir);
1617  vpImagePoint ip;
1618  ip.set_u(this->firstBorder_u);
1619  ip.set_v(this->firstBorder_v);
1620 
1621  ip_edges_list.push_back(ip);
1622 
1623  int border_u = (int)this->firstBorder_u;
1624  int border_v = (int)this->firstBorder_v;
1625 
1626  // vpTRACE("-----------------------------------------");
1627  // vpTRACE("first border_u: %d border_v: %d dir: %d",
1628  // this->firstBorder_u, this->firstBorder_v,firstDir);
1629  int du, dv;
1630  float dS, dMu, dMv, dMuv, dMu2, dMv2;
1631  m00 = 0.0;
1632  m10 = 0.0;
1633  m01 = 0.0;
1634  m11 = 0.0;
1635  m20 = 0.0;
1636  m02 = 0.0;
1637  // while we didn't come back to the first point, follow the border
1638  do {
1639  // if it was asked, show the border
1640  if (graphics) {
1641  for (int t = 0; t < (int)thickness; t++) {
1642  ip.set_u(border_u + t);
1643  ip.set_v(border_v);
1644 
1646  }
1647  // vpDisplay::flush(I);
1648  }
1649 #ifdef DEBUG
1650  vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1651  vpDisplay::flush(I);
1652 #endif
1653  // Determine the increments for the parameters
1654  computeFreemanParameters(border_u, border_v, dir, du, dv,
1655  dS, // surface
1656  dMu, dMv, // first order moments
1657  dMuv, dMu2, dMv2); // second order moment
1658 
1659  // Update the parameters
1660  border_u += du; // Next position on the border
1661  border_v += dv;
1662  m00 += dS; // enclosed area
1663  m10 += dMu; // First order moment along v axis
1664  m01 += dMv; // First order moment along u axis
1665  if (compute_moment) {
1666  m11 += dMuv; // Second order moment
1667  m20 += dMu2; // Second order moment along v axis
1668  m02 += dMv2; // Second order moment along u axis
1669  }
1670  // if we are now out of the image, return an error tracking
1671  if (!isInArea((unsigned int)border_u, (unsigned int)border_v)) {
1672 
1673  vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
1674  // Can Occur on a single pixel dot located on the top border
1675  return false;
1676  }
1677 
1678  // store the new direction and dot border coordinates.
1679 
1680  direction_list.push_back(dir);
1681 
1682  ip.set_u(border_u);
1683  ip.set_v(border_v);
1684  ip_edges_list.push_back(ip);
1685 
1686  // vpDisplay::getClick(I);
1687 
1688  // update the extreme point of the dot.
1689  if (border_v < bbox_v_min)
1690  bbox_v_min = border_v;
1691  if (border_v > bbox_v_max)
1692  bbox_v_max = border_v;
1693  if (border_u < bbox_u_min)
1694  bbox_u_min = border_u;
1695  if (border_u > bbox_u_max)
1696  bbox_u_max = border_u;
1697 
1698  // move around the tracked entity by following the border.
1699  if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
1700  vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)", border_u, border_v);
1701  return false;
1702  }
1703 
1704  // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v,
1705  // dir);
1706 
1707  } while ((getFirstBorder_u() != (unsigned int)border_u || getFirstBorder_v() != (unsigned int)border_v ||
1708  firstDir != dir) &&
1709  isInArea((unsigned int)border_u, (unsigned int)border_v));
1710 
1711 #ifdef VP_DEBUG
1712 #if VP_DEBUG_MODE == 3
1713  vpDisplay::flush(I);
1714 #endif
1715 #endif
1716 
1717  // if the surface is one or zero , the center of gravity wasn't properly
1718  // detected. Return an error tracking.
1719  // if( m00 == 0 || m00 == 1 )
1720  if (std::fabs(m00) <= std::numeric_limits<double>::epsilon() ||
1721  std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.) * std::numeric_limits<double>::epsilon()) {
1722  vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
1723  return false;
1724  } else // compute the center
1725  {
1726  // this magic formula gives the coordinates of the center of gravity
1727  double tmpCenter_u = m10 / m00;
1728  double tmpCenter_v = m01 / m00;
1729 
1730  // Updates the central moments
1731  if (compute_moment) {
1732  mu11 = m11 - tmpCenter_u * m01;
1733  mu02 = m02 - tmpCenter_v * m01;
1734  mu20 = m20 - tmpCenter_u * m10;
1735  }
1736 
1737  // check the center is in the image... never know...
1738  // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
1739  // (unsigned int)tmpCenter_v ) )
1740  // {
1741  // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has
1742  // not a good in level", tmpCenter_u, tmpCenter_v); return false;
1743  // }
1744 
1745  cog.set_u(tmpCenter_u);
1746  cog.set_v(tmpCenter_v);
1747  }
1748 
1749  width = bbox_u_max - bbox_u_min + 1;
1750  height = bbox_v_max - bbox_v_min + 1;
1751  surface = m00;
1752 
1753  computeMeanGrayLevel(I);
1754  return true;
1755 }
1756 
1772 bool vpDot2::findFirstBorder(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1773  unsigned int &border_u, unsigned int &border_v)
1774 {
1775  // find the border
1776 
1777  // NOTE:
1778  // from here we use int and not double. This is because we don't have
1779  // rounding problems and it's actually more a trouble than smth else to
1780  // work with double when navigating around the dot.
1781  border_u = u;
1782  border_v = v;
1783  double epsilon = 0.001;
1784 
1785 #ifdef DEBUG
1786  std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
1787 #endif
1788  while (hasGoodLevel(I, border_u + 1, border_v) && border_u < area.getRight() /*I.getWidth()*/) {
1789  // if the width of this dot was initialised and we already crossed the dot
1790  // on more than the max possible width, no need to continue, return an
1791  // error tracking
1792  if (getWidth() > 0 && (border_u - u) > getWidth() / (getMaxSizeSearchDistancePrecision() + epsilon)) {
1793  vpDEBUG_TRACE(3,
1794  "The found dot (%d, %d, %d) has a greater width than the "
1795  "required one",
1796  u, v, border_u);
1797  return false;
1798  }
1799 #ifdef DEBUG
1800  vpDisplay::displayPoint(I, (int)border_v, (int)border_u + 1, vpColor::green);
1801  vpDisplay::flush(I);
1802 #endif
1803 
1804  border_u++;
1805  }
1806  return true;
1807 }
1808 
1827 bool vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1828  unsigned int &element)
1829 {
1830 
1831  if (hasGoodLevel(I, u, v)) {
1832  unsigned int _u = u;
1833  unsigned int _v = v;
1834  // get the point on the right of the point passed in
1835  updateFreemanPosition(_u, _v, (element + 2) % 8);
1836  if (hasGoodLevel(I, _u, _v)) {
1837  element = (element + 2) % 8; // turn right
1838  } else {
1839  unsigned int _u1 = u;
1840  unsigned int _v1 = v;
1841  updateFreemanPosition(_u1, _v1, (element + 1) % 8);
1842 
1843  if (hasGoodLevel(I, _u1, _v1)) {
1844  element = (element + 1) % 8; // turn diag right
1845  } else {
1846  unsigned int _u2 = u;
1847  unsigned int _v2 = v;
1848  updateFreemanPosition(_u2, _v2, element); // same direction
1849 
1850  if (hasGoodLevel(I, _u2, _v2)) {
1851  // element = element; // keep same dir
1852  } else {
1853  unsigned int _u3 = u;
1854  unsigned int _v3 = v;
1855  updateFreemanPosition(_u3, _v3, (element + 7) % 8); // diag left
1856 
1857  if (hasGoodLevel(I, _u3, _v3)) {
1858  element = (element + 7) % 8; // turn diag left
1859  } else {
1860  unsigned int _u4 = u;
1861  unsigned int _v4 = v;
1862  updateFreemanPosition(_u4, _v4, (element + 6) % 8); // left
1863 
1864  if (hasGoodLevel(I, _u4, _v4)) {
1865  element = (element + 6) % 8; // turn left
1866  } else {
1867  unsigned int _u5 = u;
1868  unsigned int _v5 = v;
1869  updateFreemanPosition(_u5, _v5, (element + 5) % 8); // left
1870 
1871  if (hasGoodLevel(I, _u5, _v5)) {
1872  element = (element + 5) % 8; // turn diag down
1873  } else {
1874  unsigned int _u6 = u;
1875  unsigned int _v6 = v;
1876  updateFreemanPosition(_u6, _v6, (element + 4) % 8); // left
1877 
1878  if (hasGoodLevel(I, _u6, _v6)) {
1879  element = (element + 4) % 8; // turn down
1880  } else {
1881  unsigned int _u7 = u;
1882  unsigned int _v7 = v;
1883  updateFreemanPosition(_u7, _v7, (element + 3) % 8); // diag
1884 
1885  if (hasGoodLevel(I, _u7, _v7)) {
1886  element = (element + 3) % 8; // turn diag right down
1887  } else {
1888  // No neighbor with a good level
1889  //
1890  return false;
1891  }
1892  }
1893  }
1894  }
1895  }
1896  }
1897  }
1898  }
1899  }
1900 
1901  else {
1902  return false;
1903  }
1904 
1905  return true;
1906 }
1907 
1939 void vpDot2::computeFreemanParameters(const int &u_p, const int &v_p, unsigned int &element, int &du, int &dv,
1940  float &dS, float &dMu, float &dMv, float &dMuv, float &dMu2, float &dMv2)
1941 {
1942  du = 0;
1943  dv = 0;
1944  dMuv = 0;
1945  dMu2 = 0;
1946  dMv2 = 0;
1947 
1948  /*
1949  3 2 1
1950  \ | /
1951  \|/
1952  4 ------- 0
1953  /|\
1954  / | \
1955  5 6 7
1956  */
1957  switch (element) {
1958  case 0: // go right
1959  du = 1;
1960  dS = (float)v_p;
1961  dMu = 0.0;
1962  dMv = (float)(0.5 * v_p * v_p);
1963  if (compute_moment) {
1964  dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
1965  dMu2 = 0;
1966  dMv2 = (float)(1.0 / 3. * v_p * v_p * v_p);
1967  }
1968  break;
1969 
1970  case 1: // go right top
1971  du = 1;
1972  dv = 1;
1973  dS = (float)(v_p + 0.5);
1974  dMu = -(float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
1975  dMv = (float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
1976  if (compute_moment) {
1977  float half_u_p = (float)(0.5 * u_p);
1978  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) + v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
1979  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1. / 12.0);
1980  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1. / 12.0);
1981  }
1982  break;
1983 
1984  case 2: // go top
1985  dv = 1;
1986  dS = 0.0;
1987  dMu = (float)(-0.5 * u_p * u_p);
1988  dMv = 0.0;
1989  if (compute_moment) {
1990  dMuv = 0;
1991  dMu2 = (float)(-1.0 / 3. * u_p * u_p * u_p);
1992  dMv2 = 0;
1993  }
1994  break;
1995 
1996  case 3:
1997  du = -1;
1998  dv = 1;
1999  dS = (float)(-v_p - 0.5);
2000  dMu = -(float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2001  dMv = -(float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
2002  if (compute_moment) {
2003  float half_u_p = (float)(0.5 * u_p);
2004  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) + v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2005  dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2006  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1. / 12.0);
2007  }
2008  break;
2009 
2010  case 4:
2011  du = -1;
2012  dS = (float)(-v_p);
2013  dMv = (float)(-0.5 * v_p * v_p);
2014  dMu = 0.0;
2015  if (compute_moment) {
2016  dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2017  dMu2 = 0;
2018  dMv2 = (float)(-1.0 / 3. * v_p * v_p * v_p);
2019  }
2020  break;
2021 
2022  case 5:
2023  du = -1;
2024  dv = -1;
2025  dS = (float)(-v_p + 0.5);
2026  dMu = (float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2027  dMv = (float)(-(0.5 * v_p * (v_p - 1) + 1.0 / 6.0));
2028  if (compute_moment) {
2029  float half_u_p = (float)(0.5 * u_p);
2030  dMuv = (float)(v_p * v_p * (0.25 - half_u_p) - v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2031  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2032  dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2033  }
2034  break;
2035 
2036  case 6:
2037  dv = -1;
2038  dS = 0.0;
2039  dMu = (float)(0.5 * u_p * u_p);
2040  dMv = 0.0;
2041  if (compute_moment) {
2042  dMuv = 0;
2043  dMu2 = (float)(1.0 / 3. * u_p * u_p * u_p);
2044  dMv2 = 0;
2045  }
2046  break;
2047 
2048  case 7:
2049  du = 1;
2050  dv = -1;
2051  dS = (float)(v_p - 0.5);
2052  dMu = (float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
2053  dMv = (float)(0.5 * v_p * (v_p - 1) + 1.0 / 6.0);
2054  if (compute_moment) {
2055  float half_u_p = (float)(0.5 * u_p);
2056  dMuv = (float)(v_p * v_p * (0.25 + half_u_p) - v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
2057  dMu2 = (float)(1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1. / 12.0);
2058  dMv2 = (float)(1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2059  }
2060  break;
2061  }
2062 }
2063 
2077 void vpDot2::updateFreemanPosition(unsigned int &u, unsigned int &v, const unsigned int &dir)
2078 {
2079  switch (dir) {
2080  case 0:
2081  u += 1;
2082  break;
2083  case 1:
2084  u += 1;
2085  v += 1;
2086  break;
2087  case 2:
2088  v += 1;
2089  break;
2090  case 3:
2091  u -= 1;
2092  v += 1;
2093  break;
2094  case 4:
2095  u -= 1;
2096  break;
2097  case 5:
2098  u -= 1;
2099  v -= 1;
2100  break;
2101  case 6:
2102  v -= 1;
2103  break;
2104  case 7:
2105  u += 1;
2106  v -= 1;
2107  break;
2108  }
2109 }
2110 
2122 bool vpDot2::isInImage(const vpImage<unsigned char> &I) const { return isInImage(I, cog); }
2123 
2135 bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
2136 {
2137  unsigned int h = I.getHeight();
2138  unsigned int w = I.getWidth();
2139  double u = ip.get_u();
2140  double v = ip.get_v();
2141 
2142  if (u < 0 || u >= w)
2143  return false;
2144  if (v < 0 || v >= h)
2145  return false;
2146  return true;
2147 }
2148 
2160 bool vpDot2::isInArea(const unsigned int &u, const unsigned int &v) const
2161 {
2162  unsigned int area_u_min = (unsigned int)area.getLeft();
2163  unsigned int area_u_max = (unsigned int)area.getRight();
2164  unsigned int area_v_min = (unsigned int)area.getTop();
2165  unsigned int area_v_max = (unsigned int)area.getBottom();
2166 
2167  if (u < area_u_min || u > area_u_max)
2168  return false;
2169  if (v < area_v_min || v > area_v_max)
2170  return false;
2171  return true;
2172 }
2173 
2185 void vpDot2::getGridSize(unsigned int &gridWidth, unsigned int &gridHeight)
2186 {
2187  // first get the research grid width and height Note that
2188  // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2189  // contained in the dot. We gent this here if the dot is a perfect disc.
2190  // More accurate criterium to define the grid should be implemented if
2191  // necessary
2192  gridWidth = (unsigned int)(getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2193  gridHeight = (unsigned int)(getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2194 
2195  if (gridWidth == 0)
2196  gridWidth = 1;
2197  if (gridHeight == 0)
2198  gridHeight = 1;
2199 }
2200 
2213 void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char> &I)
2214 {
2215  int cog_u = (int)cog.get_u();
2216  int cog_v = (int)cog.get_v();
2217 
2218  unsigned int sum_value = 0;
2219  unsigned int nb_pixels = 0;
2220 
2221  for (unsigned int i = (unsigned int)this->bbox_u_min; i <= (unsigned int)this->bbox_u_max; i++) {
2222  unsigned int pixel_gray = (unsigned int)I[(unsigned int)cog_v][i];
2223  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2224  sum_value += pixel_gray;
2225  nb_pixels++;
2226  }
2227  }
2228  for (unsigned int i = (unsigned int)this->bbox_v_min; i <= (unsigned int)this->bbox_v_max; i++) {
2229  unsigned char pixel_gray = I[i][(unsigned int)cog_u];
2230  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2231  sum_value += pixel_gray;
2232  nb_pixels++;
2233  }
2234  }
2235  if (nb_pixels < 10) { // could be good to choose the min nb points from area of dot
2236  // add diagonals points to have enough point
2237  int imin, imax;
2238  if ((cog_u - bbox_u_min) > (cog_v - bbox_v_min)) {
2239  imin = cog_v - bbox_v_min;
2240  } else {
2241  imin = cog_u - bbox_u_min;
2242  }
2243  if ((bbox_u_max - cog_u) > (bbox_v_max - cog_v)) {
2244  imax = bbox_v_max - cog_v;
2245  } else {
2246  imax = bbox_u_max - cog_u;
2247  }
2248  for (int i = -imin; i <= imax; i++) {
2249  unsigned int pixel_gray = (unsigned int)I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2250  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2251  sum_value += pixel_gray;
2252  nb_pixels++;
2253  }
2254  }
2255 
2256  if ((cog_u - bbox_u_min) > (bbox_v_max - cog_v)) {
2257  imin = bbox_v_max - cog_v;
2258  } else {
2259  imin = cog_u - bbox_u_min;
2260  }
2261  if ((bbox_u_max - cog_u) > (cog_v - bbox_v_min)) {
2262  imax = cog_v - bbox_v_min;
2263  } else {
2264  imax = bbox_u_max - cog_u;
2265  }
2266 
2267  for (int i = -imin; i <= imax; i++) {
2268  unsigned char pixel_gray = I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2269  if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2270  sum_value += pixel_gray;
2271  nb_pixels++;
2272  }
2273  }
2274  }
2275 
2276  if (nb_pixels == 0) {
2277  // should never happen
2278  throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No point was found"));
2279  } else {
2280  mean_gray_level = sum_value / nb_pixels;
2281  }
2282 }
2283 
2302 vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I,
2303  vpColor col, bool trackDot)
2304 {
2305  vpMatrix Cogs(n, 2);
2306  vpImagePoint cog;
2307  unsigned int i;
2308  bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
2309  if (fromFile) {
2310  vpMatrix::loadMatrix(dotFile, Cogs);
2311  std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
2312  }
2313 
2314  // test number of cogs in file
2315  if (Cogs.getRows() < n) {
2316  std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
2317  fromFile = false;
2318  }
2319 
2320  // read from file and tracks the dots
2321  if (fromFile) {
2322  try {
2323  for (i = 0; i < n; ++i) {
2324  cog.set_uv(Cogs[i][0], Cogs[i][1]);
2325  dot[i].setGraphics(true);
2326  dot[i].setCog(cog);
2327  if (trackDot) {
2328  dot[i].initTracking(I, cog);
2329  dot[i].track(I);
2330  vpDisplay::displayCross(I, cog, 10, col);
2331  }
2332  }
2333  } catch (...) {
2334  std::cout << "Cannot track dots from file" << std::endl;
2335  fromFile = false;
2336  }
2337  vpDisplay::flush(I);
2338 
2339  // check that dots are far away ones from the other
2340  for (i = 0; i < n && fromFile; ++i) {
2341  double d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
2342  for (unsigned int j = 0; j < n && fromFile; ++j)
2343  if (j != i)
2344  if (dot[i].getDistance(dot[j]) < d) {
2345  fromFile = false;
2346  std::cout << "Dots from file seem incoherent" << std::endl;
2347  }
2348  }
2349  }
2350 
2351  if (!fromFile) {
2352  vpDisplay::display(I);
2353  vpDisplay::flush(I);
2354 
2355  std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
2356  for (i = 0; i < n; i++) {
2357  if (trackDot) {
2358  dot[i].setGraphics(true);
2359  dot[i].initTracking(I);
2360  cog = dot[i].getCog();
2361  } else {
2362  vpDisplay::getClick(I, cog);
2363  dot[i].setCog(cog);
2364  }
2365  Cogs[i][0] = cog.get_u();
2366  Cogs[i][1] = cog.get_v();
2367  vpDisplay::displayCross(I, cog, 10, col);
2368  vpDisplay::flush(I);
2369  }
2370  }
2371 
2372  if (!fromFile && (dotFile != "")) {
2373  vpMatrix::saveMatrix(dotFile, Cogs);
2374  std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
2375  }
2376 
2377  // back to non graphic mode
2378  for (i = 0; i < n; ++i)
2379  dot[i].setGraphics(false);
2380 
2381  return Cogs;
2382 }
2383 
2400 void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I,
2401  std::vector<vpImagePoint> &cogs, vpImagePoint *cogStar)
2402 {
2403  unsigned int i;
2404  // tracking
2405  for (i = 0; i < n; ++i) {
2406  dot[i].track(I);
2407  cogs.push_back(dot[i].getCog());
2408  }
2409  // trajectories
2410  for (i = n; i < cogs.size(); ++i)
2411  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::green, true);
2412  // initial position
2413  for (i = 0; i < n; ++i)
2414  vpDisplay::displayCircle(I, cogs[i], 4, vpColor::blue, true);
2415  // if exists, desired position
2416  if (cogStar != NULL)
2417  for (i = 0; i < n; ++i) {
2418  vpDisplay::displayDotLine(I, cogStar[i], dot[i].getCog(), vpColor::red);
2419  vpDisplay::displayCircle(I, cogStar[i], 4, vpColor::red, true);
2420  }
2421  vpDisplay::flush(I);
2422 }
2423 
2439  const std::list<vpImagePoint> &edges_list, vpColor color, unsigned int thickness)
2440 {
2441  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2442  std::list<vpImagePoint>::const_iterator it;
2443 
2444  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2445  vpDisplay::displayPoint(I, *it, color);
2446  }
2447 }
2448 
2463 void vpDot2::display(const vpImage<vpRGBa> &I, const vpImagePoint &cog, const std::list<vpImagePoint> &edges_list,
2464  vpColor color, unsigned int thickness)
2465 {
2466  vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2467  std::list<vpImagePoint>::const_iterator it;
2468 
2469  for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2470  vpDisplay::displayPoint(I, *it, color);
2471  }
2472 }
2473 
2479 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:104
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:175
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:969
double getHeight() const
Definition: vpDot2.cpp:620
static bool loadMatrix(const std::string &filename, vpArray2D< double > &M, const bool binary=false, char *header=NULL)
Definition: vpMatrix.h:605
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:823
double getSizePrecision() const
Definition: vpDot2.cpp:641
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1) const
Definition: vpDot2.cpp:212
Class to define colors available for display functionnalities.
Definition: vpColor.h:120
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:270
vpDot2 & operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:147
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:241
double getArea() const
Definition: vpDot2.cpp:627
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:156
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
static const vpColor green
Definition: vpColor.h:183
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
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:439
static void flush(const vpImage< unsigned char > &I)
double getRight() const
Definition: vpRect.h:162
static const vpColor red
Definition: vpColor.h:180
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:137
friend VISP_EXPORT std::ostream & operator<<(std::ostream &os, vpDot2 &d)
Definition: vpDot2.cpp:2479
void setGraphicsThickness(unsigned int t)
Definition: vpDot2.h:301
static bool checkFilename(const char *filename)
Definition: vpIoTools.cpp:573
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:725
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
void set_u(const double u)
Definition: vpImagePoint.h:226
double m20
Definition: vpDot2.h:382
#define vpTRACE
Definition: vpDebug.h:416
static double sqr(double x)
Definition: vpMath.h:108
static void display(const vpImage< unsigned char > &I)
double get_j() const
Definition: vpImagePoint.h:215
void set_v(const double v)
Definition: vpImagePoint.h:237
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:201
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:663
void setComputeMoments(const bool activate)
Definition: vpDot2.h:256
void setArea(const double &area)
Definition: vpDot2.cpp:706
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:156
vpDot2()
Definition: vpDot2.cpp:104
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:796
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:634
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:682
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:2400
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:753
unsigned int getHeight() const
Definition: vpImage.h:178
void getFreemanChain(std::list< unsigned int > &freeman_chain) const
Definition: vpDot2.cpp:1513
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:658
double getWidth() const
Definition: vpDot2.cpp:613
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:253
static bool saveMatrix(const std::string &filename, const vpArray2D< double > &M, const bool binary=false, const char *header="")
Definition: vpMatrix.h:640
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:650
void setHeight(const double &height)
Definition: vpDot2.cpp:694
double m10
Definition: vpDot2.h:359
#define vpDEBUG_TRACE
Definition: vpDebug.h:487
vpImagePoint getCog() const
Definition: vpDot2.h:161
void set_uv(const double u, const double v)
Definition: vpImagePoint.h:248
double mu20
Definition: vpDot2.h:405
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:191
void setRect(double l, double t, double w, double h)
Definition: vpRect.h:268
unsigned int getWidth() const
Definition: vpImage.h:229
double getBottom() const
Definition: vpRect.h:94
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:2302
void setGraphics(const bool activate)
Definition: vpDot2.h:294
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:186