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