Visual Servoing Platform version 3.5.0
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 *****************************************************************************/
70void 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
133vpDot2::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
212void 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
253void 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
311void 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
381void 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
441void 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
608void vpDot2::track(const vpImage<unsigned char> &I, vpImagePoint &ip, bool canMakeTheWindowGrow)
609{
610 track(I, canMakeTheWindowGrow);
611
612 ip = this->cog;
613}
614
617
623double vpDot2::getWidth() const { return width; }
624
630double vpDot2::getHeight() const { return height; }
631
637double vpDot2::getArea() const { return fabs(surface); }
638
644double vpDot2::getGrayLevelPrecision() const { return grayLevelPrecision; }
645
651double vpDot2::getSizePrecision() const { return sizePrecision; }
652
660double vpDot2::getEllipsoidShapePrecision() const { return ellipsoidShapePrecision; }
661
668double vpDot2::getMaxSizeSearchDistancePrecision() const { return maxSizeSearchDistancePrecision; }
669
673double 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
692void vpDot2::setWidth(const double &w) { this->width = w; }
693
704void vpDot2::setHeight(const double &h) { this->height = h; }
705
716void vpDot2::setArea(const double &a) { this->surface = a; }
717
735void 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}
763void 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
806void 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
833void 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
853void vpDot2::setArea(const vpImage<unsigned char> &I) { setArea(I, 0, 0, I.getWidth(), I.getHeight()); }
854
867void 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
897void vpDot2::setArea(const vpRect &a) { area = a; }
898
900
952void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, std::list<vpDot2> &niceDots)
953{
954 searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
955}
956
979void 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
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
1230bool 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 // Chaumette, Image Moments: A General and Useful Set of Features for Visual Servoing, TRO 2004, eq 15
1325
1326 // mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1327 // = m11 - m10 * m01 / m00
1328 // mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1329 // = m20 - m10^2 / m00
1330 // mu02 = m02 - m01^2 / m00
1331 // alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1332 //
1333 // a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1334 //
1335 // a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1336
1337 // we compute parameters of the estimated ellipse
1338 double tmp1 = (m01 * m01 - m10 * m10) / m00 + (m20 - m02);
1339 double tmp2 = m11 - m10 * m01 / m00;
1340 double Sqrt = sqrt(tmp1 * tmp1 + 4 * tmp2 * tmp2);
1341 double a1 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 + Sqrt));
1342 double a2 = sqrt(2 / m00 * ((m20 + m02) - (m10 * m10 + m01 * m01) / m00 - Sqrt));
1343 double alpha = 0.5 * atan2(2 * (m11 * m00 - m10 * m01), ((m20 - m02) * m00 - m10 * m10 + m01 * m01));
1344
1345 // to be able to track small dots, minorize the ellipsoid radius for the
1346 // inner test
1347 a1 -= 1.0;
1348 a2 -= 1.0;
1349
1350 double innerCoef = ellipsoidShape_precision;
1351 unsigned int u, v;
1352 double cog_u = this->cog.get_u();
1353 double cog_v = this->cog.get_v();
1354
1355 vpImagePoint ip;
1356 nb_bad_points = 0;
1357 for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1358 u = (unsigned int)(cog_u + innerCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1359 v = (unsigned int)(cog_v + innerCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1360 if (!this->hasGoodLevel(I, u, v)) {
1361// vpTRACE("Inner circle pixel (%d, %d) has bad level for dot (%g, %g)",
1362// u, v, cog_u, cog_v);
1363#ifdef DEBUG
1364 printf("Inner circle pixel (%u, %u) has bad level for dot (%g, %g): "
1365 "%d not in [%u, %u]\n",
1366 u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1367#endif
1368 // return false;
1369 nb_bad_points++;
1370 }
1371 if (graphics) {
1372 for (unsigned int t = 0; t < thickness; t++) {
1373 ip.set_u(u + t);
1374 ip.set_v(v);
1376 }
1377 }
1378#ifdef DEBUG
1381#endif
1382 }
1383 if (nb_bad_points > nb_max_bad_points) {
1384#ifdef DEBUG
1385 printf("Inner ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1386#endif
1387 return false;
1388 }
1389 // to be able to track small dots, maximize the ellipsoid radius for the
1390 // inner test
1391 a1 += 2.0;
1392 a2 += 2.0;
1393
1394 double outCoef = 2 - ellipsoidShape_precision; // 1.6;
1395 nb_bad_points = 0;
1396 for (double theta = 0.; theta < 2 * M_PI; theta += step_angle) {
1397 u = (unsigned int)(cog_u + outCoef * (a1 * cos(alpha) * cos(theta) - a2 * sin(alpha) * sin(theta)));
1398 v = (unsigned int)(cog_v + outCoef * (a1 * sin(alpha) * cos(theta) + a2 * cos(alpha) * sin(theta)));
1399#ifdef DEBUG
1400 // vpDisplay::displayRectangle(I, area, vpColor::yellow);
1401 vpDisplay::displayCross(I, (int)v, (int)u, 7, vpColor::purple);
1403#endif
1404 // If outside the area, continue
1405 if ((double)u < area.getLeft() || (double)u > area.getRight() || (double)v < area.getTop() ||
1406 (double)v > area.getBottom()) {
1407 continue;
1408 }
1409 if (!this->hasReverseLevel(I, u, v)) {
1410// vpTRACE("Outside circle pixel (%d, %d) has bad level for dot (%g,
1411// %g)", u, v, cog_u, cog_v);
1412#ifdef DEBUG
1413 printf("Outside circle pixel (%u, %u) has bad level for dot (%g, "
1414 "%g): %d not in [%u, %u]\n",
1415 u, v, cog_u, cog_v, I[v][u], gray_level_min, gray_level_max);
1416#endif
1417 nb_bad_points++;
1418 // return false;
1419 }
1420 if (graphics) {
1421 for (unsigned int t = 0; t < thickness; t++) {
1422 ip.set_u(u + t);
1423 ip.set_v(v);
1424
1426 }
1427 }
1428 }
1429 }
1430 if (nb_bad_points > nb_max_bad_points) {
1431#ifdef DEBUG
1432 printf("Outside ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1433#endif
1434 return false;
1435 }
1436
1437 return true;
1438}
1439
1458bool vpDot2::hasGoodLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1459{
1460 if (!isInArea(u, v))
1461 return false;
1462
1463 if (I[v][u] >= gray_level_min && I[v][u] <= gray_level_max) {
1464 return true;
1465 } else {
1466 return false;
1467 }
1468}
1469
1482bool vpDot2::hasReverseLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1483{
1484
1485 if (!isInArea(u, v))
1486 return false;
1487
1488 if (I[v][u] < gray_level_min || I[v][u] > gray_level_max) {
1489 return true;
1490 } else {
1491 return false;
1492 }
1493}
1494
1503vpDot2 *vpDot2::getInstance() { return new vpDot2(); }
1504
1520void vpDot2::getFreemanChain(std::list<unsigned int> &freeman_chain) const { freeman_chain = direction_list; }
1521
1522/******************************************************************************
1523 *
1524 * PRIVATE METHODS
1525 *
1526 ******************************************************************************/
1527
1559bool vpDot2::computeParameters(const vpImage<unsigned char> &I, const double &_u, const double &_v)
1560{
1561 direction_list.clear();
1562 ip_edges_list.clear();
1563
1564 double est_u = _u; // estimated
1565 double est_v = _v;
1566
1567 // if u has default value, set it to the actual center value
1568 // if( est_u == -1.0 )
1569 if (std::fabs(est_u + 1.0) <= vpMath::maximum(std::fabs(est_u), 1.) * std::numeric_limits<double>::epsilon()) {
1570 est_u = this->cog.get_u();
1571 }
1572
1573 // if v has default value, set it to the actual center value
1574 // if( est_v == -1.0 )
1575 if (std::fabs(est_v + 1.0) <= vpMath::maximum(std::fabs(est_v), 1.) * std::numeric_limits<double>::epsilon()) {
1576 est_v = this->cog.get_v();
1577 }
1578
1579 // if the estimated position of the dot is out of the image, not need to
1580 // continue, return an error tracking
1581 if (!isInArea((unsigned int)est_u, (unsigned int)est_v)) {
1582 vpDEBUG_TRACE(3,
1583 "Initial pixel coordinates (%d, %d) for dot tracking are "
1584 "not in the area",
1585 (int)est_u, (int)est_v);
1586 return false;
1587 }
1588
1589 bbox_u_min = (int)I.getWidth();
1590 bbox_u_max = 0;
1591 bbox_v_min = (int)I.getHeight();
1592 bbox_v_max = 0;
1593
1594 // if the first point doesn't have the right level then there's no point to
1595 // continue.
1596 if (!hasGoodLevel(I, (unsigned int)est_u, (unsigned int)est_v)) {
1597 vpDEBUG_TRACE(3, "Can't find a dot from pixel (%d, %d) coordinates", (int)est_u, (int)est_v);
1598 return false;
1599 }
1600
1601 // find the border
1602
1603 if (!findFirstBorder(I, (unsigned int)est_u, (unsigned int)est_v, this->firstBorder_u, this->firstBorder_v)) {
1604
1605 vpDEBUG_TRACE(3, "Can't find first border (%d, %d) coordinates", (int)est_u, (int)est_v);
1606 return false;
1607 }
1608
1609 unsigned int dir = 6;
1610
1611 // Determine the first element of the Freeman chain
1612 computeFreemanChainElement(I, this->firstBorder_u, this->firstBorder_v, dir);
1613 unsigned int firstDir = dir;
1614
1615 // if we are now out of the image, return an error tracking
1616 if (!isInArea(this->firstBorder_u, this->firstBorder_v)) {
1617 vpDEBUG_TRACE(3, "Border pixel coordinates (%d, %d) of the dot are not in the area", this->firstBorder_u,
1618 this->firstBorder_v);
1619 return false;
1620 }
1621
1622 // store the new direction and dot border coordinates.
1623 direction_list.push_back(dir);
1624 vpImagePoint ip;
1625 ip.set_u(this->firstBorder_u);
1626 ip.set_v(this->firstBorder_v);
1627
1628 ip_edges_list.push_back(ip);
1629
1630 int border_u = (int)this->firstBorder_u;
1631 int border_v = (int)this->firstBorder_v;
1632
1633 // vpTRACE("-----------------------------------------");
1634 // vpTRACE("first border_u: %d border_v: %d dir: %d",
1635 // this->firstBorder_u, this->firstBorder_v,firstDir);
1636 int du, dv;
1637 float dS, dMu, dMv, dMuv, dMu2, dMv2;
1638 m00 = 0.0;
1639 m10 = 0.0;
1640 m01 = 0.0;
1641 m11 = 0.0;
1642 m20 = 0.0;
1643 m02 = 0.0;
1644 // while we didn't come back to the first point, follow the border
1645 do {
1646 // if it was asked, show the border
1647 if (graphics) {
1648 for (int t = 0; t < (int)thickness; t++) {
1649 ip.set_u(border_u + t);
1650 ip.set_v(border_v);
1651
1653 }
1654 // vpDisplay::flush(I);
1655 }
1656#ifdef DEBUG
1657 vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1659#endif
1660 // Determine the increments for the parameters
1661 computeFreemanParameters(border_u, border_v, dir, du, dv,
1662 dS, // surface
1663 dMu, dMv, // first order moments
1664 dMuv, dMu2, dMv2); // second order moment
1665
1666 // Update the parameters
1667 border_u += du; // Next position on the border
1668 border_v += dv;
1669 m00 += dS; // enclosed area
1670 m10 += dMu; // First order moment along v axis
1671 m01 += dMv; // First order moment along u axis
1672 if (compute_moment) {
1673 m11 += dMuv; // Second order moment
1674 m20 += dMu2; // Second order moment along v axis
1675 m02 += dMv2; // Second order moment along u axis
1676 }
1677 // if we are now out of the image, return an error tracking
1678 if (!isInArea((unsigned int)border_u, (unsigned int)border_v)) {
1679
1680 vpDEBUG_TRACE(3, "Dot (%d, %d) is not in the area", border_u, border_v);
1681 // Can Occur on a single pixel dot located on the top border
1682 return false;
1683 }
1684
1685 // store the new direction and dot border coordinates.
1686
1687 direction_list.push_back(dir);
1688
1689 ip.set_u(border_u);
1690 ip.set_v(border_v);
1691 ip_edges_list.push_back(ip);
1692
1693 // vpDisplay::getClick(I);
1694
1695 // update the extreme point of the dot.
1696 if (border_v < bbox_v_min)
1697 bbox_v_min = border_v;
1698 if (border_v > bbox_v_max)
1699 bbox_v_max = border_v;
1700 if (border_u < bbox_u_min)
1701 bbox_u_min = border_u;
1702 if (border_u > bbox_u_max)
1703 bbox_u_max = border_u;
1704
1705 // move around the tracked entity by following the border.
1706 if (computeFreemanChainElement(I, (unsigned int)border_u, (unsigned int)border_v, dir) == false) {
1707 vpDEBUG_TRACE(3, "Can't compute Freeman chain for dot (%d, %d)", border_u, border_v);
1708 return false;
1709 }
1710
1711 // vpTRACE("border_u: %d border_v: %d dir: %d", border_u, border_v,
1712 // dir);
1713
1714 } while ((getFirstBorder_u() != (unsigned int)border_u || getFirstBorder_v() != (unsigned int)border_v ||
1715 firstDir != dir) &&
1716 isInArea((unsigned int)border_u, (unsigned int)border_v));
1717
1718#ifdef VP_DEBUG
1719#if VP_DEBUG_MODE == 3
1721#endif
1722#endif
1723
1724 // if the surface is one or zero , the center of gravity wasn't properly
1725 // detected. Return an error tracking.
1726 // if( m00 == 0 || m00 == 1 )
1727 if (std::fabs(m00) <= std::numeric_limits<double>::epsilon() ||
1728 std::fabs(m00 - 1.) <= vpMath::maximum(std::fabs(m00), 1.) * std::numeric_limits<double>::epsilon()) {
1729 vpDEBUG_TRACE(3, "The center of gravity of the dot wasn't properly detected");
1730 return false;
1731 } else // compute the center
1732 {
1733 // this magic formula gives the coordinates of the center of gravity
1734 double tmpCenter_u = m10 / m00;
1735 double tmpCenter_v = m01 / m00;
1736
1737 // Updates the second order centered moments
1738 if (compute_moment) {
1739 mu11 = m11 - tmpCenter_u * m01;
1740 mu02 = m02 - tmpCenter_v * m01;
1741 mu20 = m20 - tmpCenter_u * m10;
1742 }
1743
1744 // check the center is in the image... never know...
1745 // if( !hasGoodLevel( I, (unsigned int)tmpCenter_u,
1746 // (unsigned int)tmpCenter_v ) )
1747 // {
1748 // vpDEBUG_TRACE(3, "The center of gravity of the dot (%g, %g) has
1749 // not a good in level", tmpCenter_u, tmpCenter_v); return false;
1750 // }
1751
1752 cog.set_u(tmpCenter_u);
1753 cog.set_v(tmpCenter_v);
1754 }
1755
1756 width = bbox_u_max - bbox_u_min + 1;
1757 height = bbox_v_max - bbox_v_min + 1;
1758 surface = m00;
1759
1760 computeMeanGrayLevel(I);
1761 return true;
1762}
1763
1779bool vpDot2::findFirstBorder(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1780 unsigned int &border_u, unsigned int &border_v)
1781{
1782 // find the border
1783
1784 // NOTE:
1785 // from here we use int and not double. This is because we don't have
1786 // rounding problems and it's actually more a trouble than smth else to
1787 // work with double when navigating around the dot.
1788 border_u = u;
1789 border_v = v;
1790 double epsilon = 0.001;
1791
1792#ifdef DEBUG
1793 std::cout << "gray level: " << gray_level_min << " " << gray_level_max << std::endl;
1794#endif
1795 while (hasGoodLevel(I, border_u + 1, border_v) && border_u < area.getRight() /*I.getWidth()*/) {
1796 // if the width of this dot was initialised and we already crossed the dot
1797 // on more than the max possible width, no need to continue, return an
1798 // error tracking
1799 if (getWidth() > 0 && (border_u - u) > getWidth() / (getMaxSizeSearchDistancePrecision() + epsilon)) {
1800 vpDEBUG_TRACE(3,
1801 "The found dot (%d, %d, %d) has a greater width than the "
1802 "required one",
1803 u, v, border_u);
1804 return false;
1805 }
1806#ifdef DEBUG
1807 vpDisplay::displayPoint(I, (int)border_v, (int)border_u + 1, vpColor::green);
1809#endif
1810
1811 border_u++;
1812 }
1813 return true;
1814}
1815
1834bool vpDot2::computeFreemanChainElement(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1835 unsigned int &element)
1836{
1837
1838 if (hasGoodLevel(I, u, v)) {
1839 unsigned int _u = u;
1840 unsigned int _v = v;
1841 // get the point on the right of the point passed in
1842 updateFreemanPosition(_u, _v, (element + 2) % 8);
1843 if (hasGoodLevel(I, _u, _v)) {
1844 element = (element + 2) % 8; // turn right
1845 } else {
1846 unsigned int _u1 = u;
1847 unsigned int _v1 = v;
1848 updateFreemanPosition(_u1, _v1, (element + 1) % 8);
1849
1850 if (hasGoodLevel(I, _u1, _v1)) {
1851 element = (element + 1) % 8; // turn diag right
1852 } else {
1853 unsigned int _u2 = u;
1854 unsigned int _v2 = v;
1855 updateFreemanPosition(_u2, _v2, element); // same direction
1856
1857 if (hasGoodLevel(I, _u2, _v2)) {
1858 // element = element; // keep same dir
1859 } else {
1860 unsigned int _u3 = u;
1861 unsigned int _v3 = v;
1862 updateFreemanPosition(_u3, _v3, (element + 7) % 8); // diag left
1863
1864 if (hasGoodLevel(I, _u3, _v3)) {
1865 element = (element + 7) % 8; // turn diag left
1866 } else {
1867 unsigned int _u4 = u;
1868 unsigned int _v4 = v;
1869 updateFreemanPosition(_u4, _v4, (element + 6) % 8); // left
1870
1871 if (hasGoodLevel(I, _u4, _v4)) {
1872 element = (element + 6) % 8; // turn left
1873 } else {
1874 unsigned int _u5 = u;
1875 unsigned int _v5 = v;
1876 updateFreemanPosition(_u5, _v5, (element + 5) % 8); // left
1877
1878 if (hasGoodLevel(I, _u5, _v5)) {
1879 element = (element + 5) % 8; // turn diag down
1880 } else {
1881 unsigned int _u6 = u;
1882 unsigned int _v6 = v;
1883 updateFreemanPosition(_u6, _v6, (element + 4) % 8); // left
1884
1885 if (hasGoodLevel(I, _u6, _v6)) {
1886 element = (element + 4) % 8; // turn down
1887 } else {
1888 unsigned int _u7 = u;
1889 unsigned int _v7 = v;
1890 updateFreemanPosition(_u7, _v7, (element + 3) % 8); // diag
1891
1892 if (hasGoodLevel(I, _u7, _v7)) {
1893 element = (element + 3) % 8; // turn diag right down
1894 } else {
1895 // No neighbor with a good level
1896 //
1897 return false;
1898 }
1899 }
1900 }
1901 }
1902 }
1903 }
1904 }
1905 }
1906 }
1907
1908 else {
1909 return false;
1910 }
1911
1912 return true;
1913}
1914
1946void vpDot2::computeFreemanParameters(const int &u_p, const int &v_p, unsigned int &element, int &du, int &dv,
1947 float &dS, float &dMu, float &dMv, float &dMuv, float &dMu2, float &dMv2)
1948{
1949 du = 0;
1950 dv = 0;
1951 dMuv = 0;
1952 dMu2 = 0;
1953 dMv2 = 0;
1954
1955 /*
1956 3 2 1
1957 \ | /
1958 \|/
1959 4 ------- 0
1960 /|\
1961 / | \
1962 5 6 7
1963 */
1964 switch (element) {
1965 case 0: // go right
1966 du = 1;
1967 dS = (float)v_p;
1968 dMu = 0.0;
1969 dMv = (float)(0.5 * v_p * v_p);
1970 if (compute_moment) {
1971 dMuv = (float)(0.25 * v_p * v_p * (2 * u_p + 1));
1972 dMu2 = 0;
1973 dMv2 = (float)(1.0 / 3. * v_p * v_p * v_p);
1974 }
1975 break;
1976
1977 case 1: // go right top
1978 du = 1;
1979 dv = 1;
1980 dS = (float)(v_p + 0.5);
1981 dMu = -(float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
1982 dMv = (float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
1983 if (compute_moment) {
1984 float half_u_p = (float)(0.5 * u_p);
1985 dMuv = (float)(v_p * v_p * (0.25 + half_u_p) + v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
1986 dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) - 1. / 12.0);
1987 dMv2 = (float)(1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) + 1. / 12.0);
1988 }
1989 break;
1990
1991 case 2: // go top
1992 dv = 1;
1993 dS = 0.0;
1994 dMu = (float)(-0.5 * u_p * u_p);
1995 dMv = 0.0;
1996 if (compute_moment) {
1997 dMuv = 0;
1998 dMu2 = (float)(-1.0 / 3. * u_p * u_p * u_p);
1999 dMv2 = 0;
2000 }
2001 break;
2002
2003 case 3:
2004 du = -1;
2005 dv = 1;
2006 dS = (float)(-v_p - 0.5);
2007 dMu = -(float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2008 dMv = -(float)(0.5 * v_p * (v_p + 1) + 1.0 / 6.0);
2009 if (compute_moment) {
2010 float half_u_p = (float)(0.5 * u_p);
2011 dMuv = (float)(v_p * v_p * (0.25 - half_u_p) + v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2012 dMu2 = (float)(-1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2013 dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p + 1.5 * v_p + 1.) - 1. / 12.0);
2014 }
2015 break;
2016
2017 case 4:
2018 du = -1;
2019 dS = (float)(-v_p);
2020 dMv = (float)(-0.5 * v_p * v_p);
2021 dMu = 0.0;
2022 if (compute_moment) {
2023 dMuv = (float)(-0.25 * v_p * v_p * (2 * u_p - 1));
2024 dMu2 = 0;
2025 dMv2 = (float)(-1.0 / 3. * v_p * v_p * v_p);
2026 }
2027 break;
2028
2029 case 5:
2030 du = -1;
2031 dv = -1;
2032 dS = (float)(-v_p + 0.5);
2033 dMu = (float)(0.5 * u_p * (u_p - 1) + 1.0 / 6.0);
2034 dMv = (float)(-(0.5 * v_p * (v_p - 1) + 1.0 / 6.0));
2035 if (compute_moment) {
2036 float half_u_p = (float)(0.5 * u_p);
2037 dMuv = (float)(v_p * v_p * (0.25 - half_u_p) - v_p * (1. / 3. - half_u_p) - 1. / 6. * u_p + 0.125);
2038 dMu2 = (float)(1. / 3. * u_p * (u_p * u_p - 1.5 * u_p + 1.) - 1. / 12.0);
2039 dMv2 = (float)(-1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2040 }
2041 break;
2042
2043 case 6:
2044 dv = -1;
2045 dS = 0.0;
2046 dMu = (float)(0.5 * u_p * u_p);
2047 dMv = 0.0;
2048 if (compute_moment) {
2049 dMuv = 0;
2050 dMu2 = (float)(1.0 / 3. * u_p * u_p * u_p);
2051 dMv2 = 0;
2052 }
2053 break;
2054
2055 case 7:
2056 du = 1;
2057 dv = -1;
2058 dS = (float)(v_p - 0.5);
2059 dMu = (float)(0.5 * u_p * (u_p + 1) + 1.0 / 6.0);
2060 dMv = (float)(0.5 * v_p * (v_p - 1) + 1.0 / 6.0);
2061 if (compute_moment) {
2062 float half_u_p = (float)(0.5 * u_p);
2063 dMuv = (float)(v_p * v_p * (0.25 + half_u_p) - v_p * (1. / 3. + half_u_p) + 1. / 6. * u_p + 0.125);
2064 dMu2 = (float)(1. / 3. * u_p * (u_p * u_p + 1.5 * u_p + 1.) + 1. / 12.0);
2065 dMv2 = (float)(1. / 3. * v_p * (v_p * v_p - 1.5 * v_p + 1.) - 1. / 12.0);
2066 }
2067 break;
2068 }
2069}
2070
2084void vpDot2::updateFreemanPosition(unsigned int &u, unsigned int &v, const unsigned int &dir)
2085{
2086 switch (dir) {
2087 case 0:
2088 u += 1;
2089 break;
2090 case 1:
2091 u += 1;
2092 v += 1;
2093 break;
2094 case 2:
2095 v += 1;
2096 break;
2097 case 3:
2098 u -= 1;
2099 v += 1;
2100 break;
2101 case 4:
2102 u -= 1;
2103 break;
2104 case 5:
2105 u -= 1;
2106 v -= 1;
2107 break;
2108 case 6:
2109 v -= 1;
2110 break;
2111 case 7:
2112 u += 1;
2113 v -= 1;
2114 break;
2115 }
2116}
2117
2129bool vpDot2::isInImage(const vpImage<unsigned char> &I) const { return isInImage(I, cog); }
2130
2142bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
2143{
2144 unsigned int h = I.getHeight();
2145 unsigned int w = I.getWidth();
2146 double u = ip.get_u();
2147 double v = ip.get_v();
2148
2149 if (u < 0 || u >= w)
2150 return false;
2151 if (v < 0 || v >= h)
2152 return false;
2153 return true;
2154}
2155
2167bool vpDot2::isInArea(const unsigned int &u, const unsigned int &v) const
2168{
2169 unsigned int area_u_min = (unsigned int)area.getLeft();
2170 unsigned int area_u_max = (unsigned int)area.getRight();
2171 unsigned int area_v_min = (unsigned int)area.getTop();
2172 unsigned int area_v_max = (unsigned int)area.getBottom();
2173
2174 if (u < area_u_min || u > area_u_max)
2175 return false;
2176 if (v < area_v_min || v > area_v_max)
2177 return false;
2178 return true;
2179}
2180
2192void vpDot2::getGridSize(unsigned int &gridWidth, unsigned int &gridHeight)
2193{
2194 // first get the research grid width and height Note that
2195 // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
2196 // contained in the dot. We gent this here if the dot is a perfect disc.
2197 // More accurate criterium to define the grid should be implemented if
2198 // necessary
2199 gridWidth = (unsigned int)(getWidth() * getMaxSizeSearchDistancePrecision() / sqrt(2.));
2200 gridHeight = (unsigned int)(getHeight() * getMaxSizeSearchDistancePrecision() / sqrt(2.0));
2201
2202 if (gridWidth == 0)
2203 gridWidth = 1;
2204 if (gridHeight == 0)
2205 gridHeight = 1;
2206}
2207
2220void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char> &I)
2221{
2222 int cog_u = (int)cog.get_u();
2223 int cog_v = (int)cog.get_v();
2224
2225 unsigned int sum_value = 0;
2226 unsigned int nb_pixels = 0;
2227
2228 for (unsigned int i = (unsigned int)this->bbox_u_min; i <= (unsigned int)this->bbox_u_max; i++) {
2229 unsigned int pixel_gray = (unsigned int)I[(unsigned int)cog_v][i];
2230 if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2231 sum_value += pixel_gray;
2232 nb_pixels++;
2233 }
2234 }
2235 for (unsigned int i = (unsigned int)this->bbox_v_min; i <= (unsigned int)this->bbox_v_max; i++) {
2236 unsigned char pixel_gray = I[i][(unsigned int)cog_u];
2237 if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2238 sum_value += pixel_gray;
2239 nb_pixels++;
2240 }
2241 }
2242 if (nb_pixels < 10) { // could be good to choose the min nb points from area of dot
2243 // add diagonals points to have enough point
2244 int imin, imax;
2245 if ((cog_u - bbox_u_min) > (cog_v - bbox_v_min)) {
2246 imin = cog_v - bbox_v_min;
2247 } else {
2248 imin = cog_u - bbox_u_min;
2249 }
2250 if ((bbox_u_max - cog_u) > (bbox_v_max - cog_v)) {
2251 imax = bbox_v_max - cog_v;
2252 } else {
2253 imax = bbox_u_max - cog_u;
2254 }
2255 for (int i = -imin; i <= imax; i++) {
2256 unsigned int pixel_gray = (unsigned int)I[(unsigned int)(cog_v + i)][(unsigned int)(cog_u + i)];
2257 if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2258 sum_value += pixel_gray;
2259 nb_pixels++;
2260 }
2261 }
2262
2263 if ((cog_u - bbox_u_min) > (bbox_v_max - cog_v)) {
2264 imin = bbox_v_max - cog_v;
2265 } else {
2266 imin = cog_u - bbox_u_min;
2267 }
2268 if ((bbox_u_max - cog_u) > (cog_v - bbox_v_min)) {
2269 imax = cog_v - bbox_v_min;
2270 } else {
2271 imax = bbox_u_max - cog_u;
2272 }
2273
2274 for (int i = -imin; i <= imax; i++) {
2275 unsigned char pixel_gray = I[(unsigned int)(cog_v - i)][(unsigned int)(cog_u + i)];
2276 if (pixel_gray >= getGrayLevelMin() && pixel_gray <= getGrayLevelMax()) {
2277 sum_value += pixel_gray;
2278 nb_pixels++;
2279 }
2280 }
2281 }
2282
2283 if (nb_pixels == 0) {
2284 // should never happen
2286 } else {
2287 mean_gray_level = sum_value / nb_pixels;
2288 }
2289}
2290
2309vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I,
2310 vpColor col, bool trackDot)
2311{
2312 vpMatrix Cogs(n, 2);
2313 vpImagePoint cog;
2314 unsigned int i;
2315 bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
2316 if (fromFile) {
2317 vpMatrix::loadMatrix(dotFile, Cogs);
2318 std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
2319 }
2320
2321 // test number of cogs in file
2322 if (Cogs.getRows() < n) {
2323 std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
2324 fromFile = false;
2325 }
2326
2327 // read from file and tracks the dots
2328 if (fromFile) {
2329 try {
2330 for (i = 0; i < n; ++i) {
2331 cog.set_uv(Cogs[i][0], Cogs[i][1]);
2332 dot[i].setGraphics(true);
2333 dot[i].setCog(cog);
2334 if (trackDot) {
2335 dot[i].initTracking(I, cog);
2336 dot[i].track(I);
2337 vpDisplay::displayCross(I, cog, 10, col);
2338 }
2339 }
2340 } catch (...) {
2341 std::cout << "Cannot track dots from file" << std::endl;
2342 fromFile = false;
2343 }
2345
2346 // check that dots are far away ones from the other
2347 for (i = 0; i < n && fromFile; ++i) {
2348 double d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
2349 for (unsigned int j = 0; j < n && fromFile; ++j)
2350 if (j != i)
2351 if (dot[i].getDistance(dot[j]) < d) {
2352 fromFile = false;
2353 std::cout << "Dots from file seem incoherent" << std::endl;
2354 }
2355 }
2356 }
2357
2358 if (!fromFile) {
2361
2362 std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
2363 for (i = 0; i < n; i++) {
2364 if (trackDot) {
2365 dot[i].setGraphics(true);
2366 dot[i].initTracking(I);
2367 cog = dot[i].getCog();
2368 } else {
2369 vpDisplay::getClick(I, cog);
2370 dot[i].setCog(cog);
2371 }
2372 Cogs[i][0] = cog.get_u();
2373 Cogs[i][1] = cog.get_v();
2374 vpDisplay::displayCross(I, cog, 10, col);
2376 }
2377 }
2378
2379 if (!fromFile && (dotFile != "")) {
2380 vpMatrix::saveMatrix(dotFile, Cogs);
2381 std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
2382 }
2383
2384 // back to non graphic mode
2385 for (i = 0; i < n; ++i)
2386 dot[i].setGraphics(false);
2387
2388 return Cogs;
2389}
2390
2407void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I,
2408 std::vector<vpImagePoint> &cogs, vpImagePoint *cogStar)
2409{
2410 unsigned int i;
2411 // tracking
2412 for (i = 0; i < n; ++i) {
2413 dot[i].track(I);
2414 cogs.push_back(dot[i].getCog());
2415 }
2416 // trajectories
2417 for (i = n; i < cogs.size(); ++i)
2418 vpDisplay::displayCircle(I, cogs[i], 4, vpColor::green, true);
2419 // initial position
2420 for (i = 0; i < n; ++i)
2421 vpDisplay::displayCircle(I, cogs[i], 4, vpColor::blue, true);
2422 // if exists, desired position
2423 if (cogStar != NULL)
2424 for (i = 0; i < n; ++i) {
2425 vpDisplay::displayDotLine(I, cogStar[i], dot[i].getCog(), vpColor::red);
2426 vpDisplay::displayCircle(I, cogStar[i], 4, vpColor::red, true);
2427 }
2429}
2430
2446 const std::list<vpImagePoint> &edges_list, vpColor color, unsigned int thickness)
2447{
2448 vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2449 std::list<vpImagePoint>::const_iterator it;
2450
2451 for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2452 vpDisplay::displayPoint(I, *it, color);
2453 }
2454}
2455
2470void vpDot2::display(const vpImage<vpRGBa> &I, const vpImagePoint &cog, const std::list<vpImagePoint> &edges_list,
2471 vpColor color, unsigned int thickness)
2472{
2473 vpDisplay::displayCross(I, cog, 3 * thickness + 8, color, thickness);
2474 std::list<vpImagePoint>::const_iterator it;
2475
2476 for (it = edges_list.begin(); it != edges_list.end(); ++it) {
2477 vpDisplay::displayPoint(I, *it, color);
2478 }
2479}
2480
2486VISP_EXPORT std::ostream &operator<<(std::ostream &os, vpDot2 &d) { return (os << "(" << d.getCog() << ")"); }
friend std::ostream & operator<<(std::ostream &s, const vpArray2D< Type > &A)
Definition: vpArray2D.h:493
unsigned int getRows() const
Definition: vpArray2D.h:289
Class to define RGB colors available for display functionnalities.
Definition: vpColor.h:158
static const vpColor red
Definition: vpColor.h:217
static const vpColor blue
Definition: vpColor.h:223
static const vpColor purple
Definition: vpColor.h:228
static const vpColor green
Definition: vpColor.h:220
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void flush(const vpImage< unsigned char > &I)
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
static void displayDotLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
static void displayCircle(const vpImage< unsigned char > &I, const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1)
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:127
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:220
vpDot2()
Definition: vpDot2.cpp:104
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:226
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=NULL)
Definition: vpDot2.cpp:2407
void track(const vpImage< unsigned char > &I, bool canMakeTheWindowGrow=true)
Definition: vpDot2.cpp:441
double m02
Definition: vpDot2.h:415
double m01
Definition: vpDot2.h:391
virtual ~vpDot2()
Definition: vpDot2.cpp:198
void setGraphics(bool activate)
Definition: vpDot2.h:314
double mu11
Definition: vpDot2.h:424
void setMaxSizeSearchDistancePrecision(const double &maxSizeSearchDistancePrecision)
Definition: vpDot2.cpp:833
vpDot2 & operator=(const vpDot2 &twinDot)
Definition: vpDot2.cpp:147
void setGraphicsThickness(unsigned int t)
Definition: vpDot2.h:321
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:660
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
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1) const
Definition: vpDot2.cpp:212
double m20
Definition: vpDot2.h:406
double m00
Definition: vpDot2.h:375
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:351
double getArea() const
Definition: vpDot2.cpp:637
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:763
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:735
double m11
Definition: vpDot2.h:399
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:334
void getFreemanChain(std::list< unsigned int > &freeman_chain) const
Definition: vpDot2.cpp:1520
void setHeight(const double &height)
Definition: vpDot2.cpp:704
double getMaxSizeSearchDistancePrecision() const
Definition: vpDot2.cpp:668
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:260
vpImagePoint getCog() const
Definition: vpDot2.h:180
double m10
Definition: vpDot2.h:383
double getSizePrecision() const
Definition: vpDot2.cpp:651
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:644
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:290
double getDistance(const vpDot2 &distantDot) const
Definition: vpDot2.cpp:673
double mu02
Definition: vpDot2.h:434
void setWidth(const double &width)
Definition: vpDot2.cpp:692
double mu20
Definition: vpDot2.h:429
double getWidth() const
Definition: vpDot2.cpp:623
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:806
double getMeanGrayLevel() const
Definition: vpDot2.h:234
void setArea(const double &area)
Definition: vpDot2.cpp:716
void setComputeMoments(bool activate)
Definition: vpDot2.h:276
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:253
static vpMatrix defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage< unsigned char > &I, vpColor col=vpColor::blue, bool trackDot=true)
Definition: vpDot2.cpp:2309
double getHeight() const
Definition: vpDot2.cpp:630
error that can be emited by ViSP classes.
Definition: vpException.h:72
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
double get_j() const
Definition: vpImagePoint.h:214
double get_u() const
Definition: vpImagePoint.h:262
void set_u(double u)
Definition: vpImagePoint.h:225
void set_uv(double u, double v)
Definition: vpImagePoint.h:247
void set_v(double v)
Definition: vpImagePoint.h:236
double get_i() const
Definition: vpImagePoint.h:203
double get_v() const
Definition: vpImagePoint.h:273
unsigned int getWidth() const
Definition: vpImage.h:246
unsigned int getHeight() const
Definition: vpImage.h:188
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:802
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:145
static double sqr(double x)
Definition: vpMath.h:116
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:154
static bool loadMatrix(const std::string &filename, vpArray2D< double > &M, bool binary=false, char *header=NULL)
Definition: vpMatrix.h:713
static bool saveMatrix(const std::string &filename, const vpArray2D< double > &M, bool binary=false, const char *header="")
Definition: vpMatrix.h:748
Defines a rectangle in the plane.
Definition: vpRect.h:80
double getLeft() const
Definition: vpRect.h:174
void setRect(double l, double t, double w, double h)
Definition: vpRect.h:334
double getRight() const
Definition: vpRect.h:180
double getBottom() const
Definition: vpRect.h:98
double getTop() const
Definition: vpRect.h:193
Class that defines what is a feature generic tracker.
Definition: vpTracker.h:65
Error that can be emited by the vpTracker class and its derivates.
#define vpTRACE
Definition: vpDebug.h:416
#define vpDEBUG_TRACE
Definition: vpDebug.h:487