Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpDot2.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Track a white dot.
32 */
33
38
39#include <visp3/core/vpDisplay.h>
40
41// exception handling
42#include <visp3/core/vpIoTools.h>
43#include <visp3/core/vpMath.h>
44#include <visp3/core/vpTrackingException.h>
45
46#include <cmath> // std::fabs
47#include <iostream>
48#include <limits> // numeric_limits
49#include <math.h>
50#include <visp3/blob/vpDot2.h>
51
53
54/******************************************************************************
55 *
56 * CONSTRUCTORS AND DESTRUCTORS
57 */
63void vpDot2::init()
64{
65 const unsigned int val_max = 255;
66 const unsigned int val_median = 128;
67 m_cog.set_u(0);
68 m_cog.set_v(0);
69
70 m_width = 0;
71 m_height = 0;
72 m_surface = 0;
73 m_mean_gray_level = 0;
74 m_gray_level_min = val_median;
75 m_gray_level_max = val_max;
76 m_grayLevelPrecision = 0.80;
77 m_gamma = 1.5;
78
79 m_sizePrecision = 0.65;
80 m_ellipsoidShapePrecision = 0.65;
81 m_maxSizeSearchDistPrecision = 0.65;
83 m00 = 0.;
84 m11 = 0.;
85 m02 = 0.;
86 m20 = 0.;
87 m10 = 0.;
88 m01 = 0.;
89 mu11 = 0.;
90 mu02 = 0.;
91 mu20 = 0.;
92
93 m_bbox_u_min = 0;
94 m_bbox_u_max = 0;
95 m_bbox_v_min = 0;
96 m_bbox_v_max = 0;
97
98 m_firstBorder_u = 0;
99 m_firstBorder_v = 0;
100
101 m_compute_moment = false;
102 m_graphics = false;
103 m_thickness = 1;
104}
105
110 : m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), m_cog(), m_width(0), m_height(0),
111 m_surface(0), m_mean_gray_level(0), m_grayLevelPrecision(0.8), m_gamma(1.5),
112 m_sizePrecision(0.65), m_ellipsoidShapePrecision(0.65), m_maxSizeSearchDistPrecision(0.65),
113 m_allowedBadPointsPercentage(0.), m_area(), m_direction_list(), m_ip_edges_list(), m_compute_moment(false), m_graphics(false),
114 m_thickness(1), m_bbox_u_min(0), m_bbox_u_max(0), m_bbox_v_min(0), m_bbox_v_max(0), m_firstBorder_u(0), m_firstBorder_v()
115{
116 const unsigned int val_max = 255;
117 const unsigned int val_median = 128;
118 m_gray_level_min = val_median;
119 m_gray_level_max = val_max;
120}
121
131 : m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), m_cog(ip), m_width(0), m_height(0),
132 m_surface(0), m_mean_gray_level(0), m_grayLevelPrecision(0.8), m_gamma(1.5),
133 m_sizePrecision(0.65), m_ellipsoidShapePrecision(0.65), m_maxSizeSearchDistPrecision(0.65),
134 m_allowedBadPointsPercentage(0.), m_area(), m_direction_list(), m_ip_edges_list(), m_compute_moment(false), m_graphics(false),
135 m_thickness(1), m_bbox_u_min(0), m_bbox_u_max(0), m_bbox_v_min(0), m_bbox_v_max(0), m_firstBorder_u(0), m_firstBorder_v()
136{
137 const unsigned int val_max = 255;
138 const unsigned int val_median = 128;
139 m_gray_level_min = val_median;
140 m_gray_level_max = val_max;
141}
142
146vpDot2::vpDot2(const vpDot2 &twinDot)
147 : vpTracker(twinDot), m00(0.), m10(0.), m01(0.), m11(0.), m20(0.), m02(0.), mu11(0.), mu20(0.), mu02(0.), m_cog(),
148 m_width(0), m_height(0), m_surface(0), m_mean_gray_level(0),
149 m_grayLevelPrecision(0.8), m_gamma(1.5), m_sizePrecision(0.65), m_ellipsoidShapePrecision(0.65),
150 m_maxSizeSearchDistPrecision(0.65), m_allowedBadPointsPercentage(0.), m_area(), m_direction_list(), m_ip_edges_list(),
151 m_compute_moment(false), m_graphics(false), m_thickness(1), m_bbox_u_min(0), m_bbox_u_max(0), m_bbox_v_min(0), m_bbox_v_max(0),
152 m_firstBorder_u(0), m_firstBorder_v()
153{
154 const unsigned int val_max = 255;
155 const unsigned int val_median = 128;
156 m_gray_level_min = val_median;
157 m_gray_level_max = val_max;
158 *this = twinDot;
159}
160
165{
166 m_cog = twinDot.m_cog;
167
168 m_width = twinDot.m_width;
169 m_height = twinDot.m_height;
170 m_surface = twinDot.m_surface;
171 m_gray_level_min = twinDot.m_gray_level_min;
172 m_gray_level_max = twinDot.m_gray_level_max;
173 m_mean_gray_level = twinDot.m_mean_gray_level;
174 m_grayLevelPrecision = twinDot.m_grayLevelPrecision;
175 m_gamma = twinDot.m_gamma;
176
177 m_sizePrecision = twinDot.m_sizePrecision;
178 m_ellipsoidShapePrecision = twinDot.m_ellipsoidShapePrecision;
179 m_maxSizeSearchDistPrecision = twinDot.m_maxSizeSearchDistPrecision;
180 m_allowedBadPointsPercentage = twinDot.m_allowedBadPointsPercentage;
181 m_area = twinDot.m_area;
182
183 m_direction_list = twinDot.m_direction_list;
184 m_ip_edges_list = twinDot.m_ip_edges_list;
185
186 m_compute_moment = twinDot.m_compute_moment;
187 m_graphics = twinDot.m_graphics;
188 m_thickness = twinDot.m_thickness;
189
190 m_bbox_u_min = twinDot.m_bbox_u_min;
191 m_bbox_u_max = twinDot.m_bbox_u_max;
192 m_bbox_v_min = twinDot.m_bbox_v_min;
193 m_bbox_v_max = twinDot.m_bbox_v_max;
194
195 m_firstBorder_u = twinDot.m_firstBorder_u;
196 m_firstBorder_v = twinDot.m_firstBorder_v;
197
198 m00 = twinDot.m00;
199 m01 = twinDot.m01;
200 m11 = twinDot.m11;
201 m10 = twinDot.m10;
202 m02 = twinDot.m02;
203 m20 = twinDot.m20;
204
205 mu11 = twinDot.mu11;
206 mu20 = twinDot.mu20;
207 mu02 = twinDot.mu02;
208
209 return (*this);
210}
211
219void vpDot2::display(const vpImage<unsigned char> &I, vpColor color, unsigned int t) const
220{
221 const unsigned int val_3 = 3;
222 const unsigned int val_8 = 8;
223 vpDisplay::displayCross(I, m_cog, (val_3 * t) + val_8, color, t);
224 std::list<vpImagePoint>::const_iterator it;
225
226 std::list<vpImagePoint>::const_iterator ip_edges_list_end = m_ip_edges_list.end();
227 for (it = m_ip_edges_list.begin(); it != ip_edges_list_end; ++it) {
228 vpDisplay::displayPoint(I, *it, color);
229 }
230}
231
263void vpDot2::initTracking(const vpImage<unsigned char> &I, unsigned int size)
264{
265 while (vpDisplay::getClick(I, m_cog) != true) {
266 // block empty waiting user interaction
267 }
268
269 unsigned int i = static_cast<unsigned int>(m_cog.get_i());
270 unsigned int j = static_cast<unsigned int>(m_cog.get_j());
271 const unsigned int val_max = 255;
272
273 double Ip = pow(static_cast<double>(I[i][j]) / val_max, 1 / m_gamma);
274
275 if ((Ip - (1 - m_grayLevelPrecision)) < 0) {
276 m_gray_level_min = 0;
277 }
278 else {
279 m_gray_level_min = static_cast<unsigned int>(val_max * pow(Ip - (1 - m_grayLevelPrecision), m_gamma));
280 if (m_gray_level_min > val_max) {
281 m_gray_level_min = val_max;
282 }
283 }
284 m_gray_level_max = static_cast<unsigned int>(val_max * pow(Ip + (1 - m_grayLevelPrecision), m_gamma));
285 if (m_gray_level_max > val_max) {
286 m_gray_level_max = val_max;
287 }
288
289 setWidth(size);
290 setHeight(size);
291
292 track(I);
293}
294
322void vpDot2::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip, unsigned int size)
323{
324 m_cog = ip;
325
326 unsigned int i = static_cast<unsigned int>(m_cog.get_i());
327 unsigned int j = static_cast<unsigned int>(m_cog.get_j());
328 const unsigned int val_max = 255;
329
330 double Ip = pow(static_cast<double>(I[i][j]) / val_max, 1 / m_gamma);
331
332 if ((Ip - (1 - m_grayLevelPrecision)) < 0) {
333 m_gray_level_min = 0;
334 }
335 else {
336 m_gray_level_min = static_cast<unsigned int>(val_max * pow(Ip - (1 - m_grayLevelPrecision), m_gamma));
337 if (m_gray_level_min > val_max) {
338 m_gray_level_min = val_max;
339 }
340 }
341 m_gray_level_max = static_cast<unsigned int>(val_max * pow(Ip + (1 - m_grayLevelPrecision), m_gamma));
342 if (m_gray_level_max > val_max) {
343 m_gray_level_max = val_max;
344 }
345
346 setWidth(size);
347 setHeight(size);
348
349 track(I);
350}
351
391void vpDot2::initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip, unsigned int gray_lvl_min,
392 unsigned int gray_lvl_max, unsigned int size)
393{
394 m_cog = ip;
395
396 m_gray_level_min = gray_lvl_min;
397 m_gray_level_max = gray_lvl_max;
398
399 setWidth(size);
400 setHeight(size);
401
402 track(I);
403}
404
441void vpDot2::track(const vpImage<unsigned char> &I, bool canMakeTheWindowGrow)
442{
443 m00 = 0;
444 m11 = 0;
445 m02 = 0;
446 m20 = 0;
447 m10 = 0;
448 m01 = 0;
449
450 // First, we will estimate the position of the tracked point
451
452 // Set the search area to the entire image
453 setArea(I);
454
455 // create a copy of the dot to search
456 // This copy can be saw as the previous dot used to check if the current one
457 // found with computeParameters() is similar to the previous one (see
458 // isValid() function). If the found dot is not similar (or valid), we use
459 // this copy to set the current found dot to the previous one (see below).
460 vpDot2 wantedDot(*this);
461
462 bool found = computeParameters(I, m_cog.get_u(), m_cog.get_v());
463
464 if (found) {
465 // test if the found dot is valid (ie similar to the previous one)
466 found = isValid(I, wantedDot);
467 if (!found) {
468 *this = wantedDot;
469 // std::cout << "The found dot is not valid" << std::endl;
470 }
471 }
472
473 if (!found) {
474 // if estimation was wrong (get an error tracking), look for the dot
475 // closest from the estimation,
476 // i.e. search for dots in an a region of interest around the this dot and
477 // get the first element in the area.
478
479 // first get the size of the search window from the dot size
480 double searchWindowWidth = 0.0;
481 double searchWindowHeight = 0.0;
482
483 if ((std::fabs(getWidth()) <= std::numeric_limits<double>::epsilon()) ||
484 (std::fabs(getHeight()) <= std::numeric_limits<double>::epsilon())) {
485 searchWindowWidth = 80.;
486 searchWindowHeight = 80.;
487 }
488 else if (canMakeTheWindowGrow) {
489 const unsigned int val_5 = 5;
490 searchWindowWidth = getWidth() * val_5;
491 searchWindowHeight = getHeight() * val_5;
492 }
493 else {
494 searchWindowWidth = getWidth();
495 searchWindowHeight = getHeight();
496 }
497
498 std::list<vpDot2> candidates;
499 searchDotsInArea(I, static_cast<int>(m_cog.get_u() - (searchWindowWidth / 2.0)),
500 static_cast<int>(m_cog.get_v() - (searchWindowHeight / 2.0)),
501 static_cast<unsigned int>(searchWindowWidth),
502 static_cast<unsigned int>(searchWindowHeight), candidates);
503
504 // if the vector is empty, that mean we didn't find any candidate
505 // in the area, return an error tracking.
506 if (candidates.empty()) {
508 }
509
510 // otherwise we've got our dot, update this dot's parameters
511 vpDot2 movingDot = candidates.front();
512
513 setCog(movingDot.getCog());
514 setArea(movingDot.getArea());
515 setWidth(movingDot.getWidth());
516 setHeight(movingDot.getHeight());
517
518 // Update the moments
519 m00 = movingDot.m00;
520 m01 = movingDot.m01;
521 m10 = movingDot.m10;
522 m11 = movingDot.m11;
523 m20 = movingDot.m20;
524 m02 = movingDot.m02;
525
526 // Update the bounding box
527 m_bbox_u_min = movingDot.m_bbox_u_min;
528 m_bbox_u_max = movingDot.m_bbox_u_max;
529 m_bbox_v_min = movingDot.m_bbox_v_min;
530 m_bbox_v_max = movingDot.m_bbox_v_max;
531 }
532
533 // if this dot is partially out of the image, return an error tracking.
534 if (!isInImage(I)) {
536 "The center of gravity of the dot is not in the image"));
537 }
538
539 const unsigned int val_max = 255;
540 double Ip = pow(getMeanGrayLevel() / val_max, 1 / m_gamma);
541 // printf("current value of gray level center : %i\n", I[v][u]);
542
543 // get Mean Gray Level of I
544 if ((Ip - (1 - m_grayLevelPrecision)) < 0) {
545 m_gray_level_min = 0;
546 }
547 else {
548 m_gray_level_min = static_cast<unsigned int>(val_max * pow(Ip - (1 - m_grayLevelPrecision), m_gamma));
549 if (m_gray_level_min > val_max) {
550 m_gray_level_min = val_max;
551 }
552 }
553 m_gray_level_max = static_cast<unsigned int>(val_max * pow(Ip + (1 - m_grayLevelPrecision), m_gamma));
554 if (m_gray_level_max > val_max) {
555 m_gray_level_max = val_max;
556 }
557
558 if (m_graphics) {
559 // display a red cross at the center of gravity's location in the image.
560 const unsigned int val_3 = 3;
561 const unsigned int val_8 = 8;
562 vpDisplay::displayCross(I, m_cog, (val_3 * m_thickness) + val_8, vpColor::red, m_thickness);
563 }
564}
565
588void vpDot2::track(const vpImage<unsigned char> &I, vpImagePoint &ip, bool canMakeTheWindowGrow)
589{
590 track(I, canMakeTheWindowGrow);
591
592 ip = m_cog;
593}
594
597
603double vpDot2::getWidth() const { return m_width; }
604
610double vpDot2::getHeight() const { return m_height; }
611
617double vpDot2::getArea() const { return fabs(m_surface); }
618
624double vpDot2::getGrayLevelPrecision() const { return m_grayLevelPrecision; }
625
631double vpDot2::getSizePrecision() const { return m_sizePrecision; }
632
640double vpDot2::getEllipsoidShapePrecision() const { return m_ellipsoidShapePrecision; }
641
648double vpDot2::getMaxSizeSearchDistPrecision() const { return m_maxSizeSearchDistPrecision; }
649
653double vpDot2::getDistance(const vpDot2 &distantDot) const
654{
655 vpImagePoint cogDistantDot = distantDot.getCog();
656 double diff_u = m_cog.get_u() - cogDistantDot.get_u();
657 double diff_v = m_cog.get_v() - cogDistantDot.get_v();
658 return sqrt((diff_u * diff_u) + (diff_v * diff_v));
659}
660
662
672void vpDot2::setWidth(const double &w) { m_width = w; }
673
684void vpDot2::setHeight(const double &h) { m_height = h; }
685
696void vpDot2::setArea(const double &a) { m_surface = a; }
697
715void vpDot2::setGrayLevelPrecision(const double &precision)
716{
717 double epsilon = 0.05;
718 if (m_grayLevelPrecision < epsilon) {
719 m_grayLevelPrecision = epsilon;
720 }
721 else if (m_grayLevelPrecision > 1) {
722 m_grayLevelPrecision = 1.0;
723 }
724 else {
725 m_grayLevelPrecision = precision;
726 }
727}
728
745void vpDot2::setSizePrecision(const double &precision)
746{
747 if (m_sizePrecision < 0) {
748 m_sizePrecision = 0;
749 }
750 else if (m_sizePrecision > 1) {
751 m_sizePrecision = 1.0;
752 }
753 else {
754 m_sizePrecision = precision;
755 }
756}
757
790void vpDot2::setEllipsoidShapePrecision(const double &precision)
791{
792
793 if (m_ellipsoidShapePrecision < 0) {
794 m_ellipsoidShapePrecision = 0;
795 }
796 else if (m_ellipsoidShapePrecision > 1) {
797 m_ellipsoidShapePrecision = 1.0;
798 }
799 else {
800 m_ellipsoidShapePrecision = precision;
801 }
802}
803
819void vpDot2::setMaxSizeSearchDistPrecision(const double &precision)
820{
821 double epsilon = 0.05;
822 if (m_maxSizeSearchDistPrecision < epsilon) {
823 m_maxSizeSearchDistPrecision = epsilon;
824 }
825 else if (m_maxSizeSearchDistPrecision > 1) {
826 m_maxSizeSearchDistPrecision = 1.0;
827 }
828 else {
829 m_maxSizeSearchDistPrecision = precision;
830 }
831}
832
841void vpDot2::setArea(const vpImage<unsigned char> &I) { setArea(I, 0, 0, I.getWidth(), I.getHeight()); }
842
855void vpDot2::setArea(const vpImage<unsigned char> &I, int u, int v, unsigned int w, unsigned int h)
856{
857 unsigned int image_w = I.getWidth();
858 unsigned int image_h = I.getHeight();
859
860 // Bounds the area to the image
861 if (u < 0) {
862 u = 0;
863 }
864 else if (u >= static_cast<int>(image_w)) {
865 u = static_cast<int>(image_w) - 1;
866 }
867 if (v < 0) {
868 v = 0;
869 }
870 else if (v >= static_cast<int>(image_h)) {
871 v = static_cast<int>(image_h) - 1;
872 }
873
874 if ((static_cast<unsigned int>(u) + w) > image_w) {
875 w = image_w - static_cast<unsigned int>(u) - 1;
876 }
877 if ((static_cast<unsigned int>(v) + h) > image_h) {
878 h = image_h - static_cast<unsigned int>(v) - 1;
879 }
880
881 m_area.setRect(u, v, w, h);
882}
883
889void vpDot2::setArea(const vpRect &area) { m_area = area; }
890
892
942void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, std::list<vpDot2> &niceDots)
943{
944 searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), niceDots);
945}
946
967bool vpDot2::isValid(const vpImage<unsigned char> &I, const vpDot2 &wantedDot)
968{
969 double size_precision = wantedDot.getSizePrecision();
970 double ellipsoidShape_precision = wantedDot.getEllipsoidShapePrecision();
971
972 //
973 // First, check the width, height and surface of the dot. Those parameters
974 // must be the same.
975 //
976 // if ( (wantedDot.getWidth() != 0)
977 // && (wantedDot.getHeight() != 0)
978 // && (wantedDot.getArea() != 0) )
979 if ((std::fabs(wantedDot.getWidth()) > std::numeric_limits<double>::epsilon()) &&
980 (std::fabs(wantedDot.getHeight()) > std::numeric_limits<double>::epsilon()) &&
981 (std::fabs(wantedDot.getArea()) > std::numeric_limits<double>::epsilon())) {
982 if (std::fabs(size_precision) > std::numeric_limits<double>::epsilon()) {
983 double epsilon = 0.001;
984#ifdef DEBUG
985 std::cout << "test size precision......................\n";
986 std::cout << "wanted dot: "
987 << "w=" << wantedDot.getWidth() << " h=" << wantedDot.getHeight() << " s=" << wantedDot.getArea()
988 << " precision=" << size_precision << " epsilon=" << epsilon << std::endl;
989 std::cout << "dot found: "
990 << "w=" << getWidth() << " h=" << getHeight() << " s=" << getArea() << std::endl;
991#endif
992
993 if ((((wantedDot.getWidth() * size_precision) - epsilon) < getWidth()) == false) {
994#ifdef DEBUG
995 printf("Bad width > for dot (%g, %g)\n", m_cog.get_u(), m_cog.get_v());
996#endif
997 return false;
998 }
999
1000 if ((getWidth() < (wantedDot.getWidth() / (size_precision + epsilon))) == false) {
1001#ifdef DEBUG
1002 printf("Bad width %g > %g for dot (%g, %g)\n", getWidth(), wantedDot.getWidth() / (size_precision + epsilon),
1003 m_cog.get_u(), m_cog.get_v());
1004#endif
1005 return false;
1006 }
1007
1008 if ((((wantedDot.getHeight() * size_precision) - epsilon) < getHeight()) == false) {
1009#ifdef DEBUG
1010 printf("Bad height %g > %g for dot (%g, %g)\n", wantedDot.getHeight() * size_precision - epsilon, getHeight(),
1011 m_cog.get_u(), m_cog.get_v());
1012#endif
1013 return false;
1014 }
1015
1016 if ((getHeight() < (wantedDot.getHeight() / (size_precision + epsilon))) == false) {
1017#ifdef DEBUG
1018 printf("Bad height %g > %g for dot (%g, %g)\n", getHeight(), wantedDot.getHeight() / (size_precision + epsilon),
1019 m_cog.get_u(), m_cog.get_v());
1020#endif
1021 return false;
1022 }
1023
1024 if ((((wantedDot.getArea() * (size_precision * size_precision)) - epsilon) < getArea()) == false) {
1025#ifdef DEBUG
1026 printf("Bad surface %g > %g for dot (%g, %g)\n",
1027 wantedDot.getArea() * (size_precision * size_precision) - epsilon, getArea(), m_cog.get_u(), m_cog.get_v());
1028#endif
1029 return false;
1030 }
1031
1032 if ((getArea() < (wantedDot.getArea() / ((size_precision * size_precision) + epsilon))) == false) {
1033#ifdef DEBUG
1034 printf("Bad surface %g < %g for dot (%g, %g)\n", getArea(),
1035 wantedDot.getArea() / (size_precision * size_precision + epsilon), m_cog.get_u(), m_cog.get_v());
1036#endif
1037 return false;
1038 }
1039 }
1040 }
1041 //
1042 // Now we can proceed to more advanced (and costy) checks.
1043 // First check there is a white (>level) elipse within dot
1044 // Then check the dot is surrounded by a black ellipse.
1045 //
1046 int nb_point_to_test = 20; // Nb points to test on inner and outside ellipsoid
1047 int nb_bad_points = 0;
1048 int nb_max_bad_points = static_cast<int>(nb_point_to_test * m_allowedBadPointsPercentage);
1049 double step_angle = (2 * M_PI) / nb_point_to_test;
1050
1051 // --comment: if ellipsoidShape_precision diff 0 and compute_moment is true
1052 if ((std::fabs(ellipsoidShape_precision) > std::numeric_limits<double>::epsilon()) && m_compute_moment) {
1053 // Chaumette, Image Moments: A General and Useful Set of Features for Visual Servoing, TRO 2004, eq 15
1054
1055 /*
1056 // -comment: mu11 = m11 - m00 * xg * yg = m11 - m00 * m10/m00 * m01/m00
1057 // -comment: = m11 - m10 * m01 / m00
1058 // -comment: mu20 = m20 - m00 * xg^2 = m20 - m00 * m10/m00 * m10/m00
1059 // -comment: = m20 - m10^2 / m00
1060 // -comment: mu02 = m02 - m01^2 / m00
1061 // -comment: alpha = 1/2 arctan( 2 * mu11 / (mu20 - mu02) )
1062 //
1063 // -comment: a1^2 = 2 / m00 * (mu02 + mu20 + sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1064 //
1065 // -comment: a2^2 = 2 / m00 * (mu02 + mu20 - sqrt( (mu20 - mu02)^2 + 4mu11^2) )
1066 */
1067 // we compute parameters of the estimated ellipse
1068 double tmp1 = (((m01 * m01) - (m10 * m10)) / m00) + (m20 - m02);
1069 double tmp2 = m11 - ((m10 * m01) / m00);
1070 double Sqrt = sqrt((tmp1 * tmp1) + (4 * tmp2 * tmp2));
1071 double a1 = sqrt((2 / m00) * (((m20 + m02) - (((m10 * m10) + (m01 * m01)) / m00)) + Sqrt));
1072 double a2 = sqrt((2 / m00) * (((m20 + m02) - (((m10 * m10) + (m01 * m01)) / m00)) - Sqrt));
1073 double alpha = 0.5 * atan2(2 * ((m11 * m00) - (m10 * m01)), ((((m20 - m02) * m00) - (m10 * m10)) + (m01 * m01)));
1074
1075 // to be able to track small dots, minorize the ellipsoid radius for the
1076 // inner test
1077 a1 -= 1.0;
1078 a2 -= 1.0;
1079
1080 double innerCoef = ellipsoidShape_precision;
1081 unsigned int u, v;
1082 double cog_u = m_cog.get_u();
1083 double cog_v = m_cog.get_v();
1084 double val_2 = 2;
1085
1086 vpImagePoint ip;
1087 nb_bad_points = 0;
1088 for (double theta = 0.; theta < (val_2 * M_PI); theta += step_angle) {
1089 u = static_cast<unsigned int>(cog_u + (innerCoef * ((a1 * cos(alpha) * cos(theta)) - (a2 * sin(alpha) * sin(theta)))));
1090 v = static_cast<unsigned int>(cog_v + (innerCoef * ((a1 * sin(alpha) * cos(theta)) + (a2 * cos(alpha) * sin(theta)))));
1091 if (!this->hasGoodLevel(I, u, v)) {
1092#ifdef DEBUG
1093 printf("Inner circle pixel (%u, %u) has bad level for dot (%g, %g): "
1094 "%d not in [%u, %u]\n",
1095 u, v, cog_u, cog_v, I[v][u], m_gray_level_min, m_gray_level_max);
1096#endif
1097 ++nb_bad_points;
1098 }
1099 if (m_graphics) {
1100 for (unsigned int t = 0; t < m_thickness; ++t) {
1101 ip.set_u(u + t);
1102 ip.set_v(v);
1104 }
1105 }
1106#ifdef DEBUG
1109#endif
1110 }
1111 if (nb_bad_points > nb_max_bad_points) {
1112#ifdef DEBUG
1113 printf("Inner ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1114#endif
1115 return false;
1116 }
1117 // to be able to track small dots, maximize the ellipsoid radius for the
1118 // inner test
1119 a1 += 2.0;
1120 a2 += 2.0;
1121
1122 double outCoef = 2 - ellipsoidShape_precision; // --comment: 1.6
1123 nb_bad_points = 0;
1124 for (double theta = 0.; theta < (val_2 * M_PI); theta += step_angle) {
1125 u = static_cast<unsigned int>(cog_u + (outCoef * ((a1 * cos(alpha) * cos(theta)) - (a2 * sin(alpha) * sin(theta)))));
1126 v = static_cast<unsigned int>(cog_v + (outCoef * ((a1 * sin(alpha) * cos(theta)) + (a2 * cos(alpha) * sin(theta)))));
1127#ifdef DEBUG
1128 // vpDisplay::displayRectangle(I, area, vpColor::yellow);
1129 vpDisplay::displayCross(I, static_cast<int>(v), static_cast<int>(u), 7, vpColor::purple);
1131#endif
1132 // If outside the area, continue
1133 if ((static_cast<double>(u) < m_area.getLeft()) ||
1134 (static_cast<double>(u) > m_area.getRight()) ||
1135 (static_cast<double>(v) < m_area.getTop()) ||
1136 (static_cast<double>(v) > m_area.getBottom())) {
1137 // continue
1138 }
1139 else {
1140 if (!this->hasReverseLevel(I, u, v)) {
1141#ifdef DEBUG
1142 printf("Outside circle pixel (%u, %u) has bad level for dot (%g, "
1143 "%g): %d not in [%u, %u]\n",
1144 u, v, cog_u, cog_v, I[v][u], m_gray_level_min, m_gray_level_max);
1145#endif
1146 ++nb_bad_points;
1147 }
1148 if (m_graphics) {
1149 for (unsigned int t = 0; t < m_thickness; ++t) {
1150 ip.set_u(u + t);
1151 ip.set_v(v);
1152
1154 }
1155 }
1156 }
1157 }
1158 }
1159 if (nb_bad_points > nb_max_bad_points) {
1160#ifdef DEBUG
1161 printf("Outside ellipse has %d bad points. Max allowed is %d\n", nb_bad_points, nb_max_bad_points);
1162#endif
1163 return false;
1164 }
1165
1166 return true;
1167}
1168
1187bool vpDot2::hasGoodLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1188{
1189 if (!isInArea(u, v)) {
1190 return false;
1191 }
1192
1193 if ((I[v][u] >= m_gray_level_min) && (I[v][u] <= m_gray_level_max)) {
1194 return true;
1195 }
1196 else {
1197 return false;
1198 }
1199}
1200
1213bool vpDot2::hasReverseLevel(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v) const
1214{
1215
1216 if (!isInArea(u, v)) {
1217 return false;
1218 }
1219
1220 if ((I[v][u] < m_gray_level_min) || (I[v][u] > m_gray_level_max)) {
1221 return true;
1222 }
1223 else {
1224 return false;
1225 }
1226}
1227
1235vpDot2 *vpDot2::getInstance() { return new vpDot2(); }
1236
1267bool vpDot2::computeParameters(const vpImage<unsigned char> &I, const double &v_u, const double &v_v)
1268{
1269 m_direction_list.clear();
1270 m_ip_edges_list.clear();
1271
1272 double est_u = v_u; // estimated
1273 double est_v = v_v;
1274
1275 // if u has default value, set it to the actual center value
1276 // if( est_u == -1.0 )
1277 if (std::fabs(est_u + 1.0) <= (vpMath::maximum(std::fabs(est_u), 1.) * std::numeric_limits<double>::epsilon())) {
1278 est_u = m_cog.get_u();
1279 }
1280
1281 // if v has default value, set it to the actual center value
1282 // if( est_v == -1.0 )
1283 if (std::fabs(est_v + 1.0) <= (vpMath::maximum(std::fabs(est_v), 1.) * std::numeric_limits<double>::epsilon())) {
1284 est_v = m_cog.get_v();
1285 }
1286
1287 // if the estimated position of the dot is out of the image, not need to
1288 // continue, return an error tracking
1289 if (!isInArea(static_cast<unsigned int>(est_u), static_cast<unsigned int>(est_v))) {
1290 return false;
1291 }
1292
1293 m_bbox_u_min = static_cast<int>(I.getWidth());
1294 m_bbox_u_max = 0;
1295 m_bbox_v_min = static_cast<int>(I.getHeight());
1296 m_bbox_v_max = 0;
1297
1298 // if the first point doesn't have the right level then there's no point to
1299 // continue.
1300 if (!hasGoodLevel(I, static_cast<unsigned int>(est_u), static_cast<unsigned int>(est_v))) {
1301 return false;
1302 }
1303
1304 // find the border
1305
1306 if (!findFirstBorder(I, static_cast<unsigned int>(est_u), static_cast<unsigned int>(est_v), m_firstBorder_u, m_firstBorder_v)) {
1307 return false;
1308 }
1309
1310 unsigned int dir = 6;
1311
1312 // Determine the first element of the Freeman chain
1313 computeFreemanChainElement(I, m_firstBorder_u, m_firstBorder_v, dir);
1314 unsigned int firstDir = dir;
1315
1316 // if we are now out of the image, return an error tracking
1317 if (!isInArea(m_firstBorder_u, m_firstBorder_v)) {
1318 return false;
1319 }
1320
1321 // store the new direction and dot border coordinates.
1322 m_direction_list.push_back(dir);
1323 vpImagePoint ip;
1324 ip.set_u(m_firstBorder_u);
1325 ip.set_v(m_firstBorder_v);
1326
1327 m_ip_edges_list.push_back(ip);
1328
1329 int border_u = static_cast<int>(m_firstBorder_u);
1330 int border_v = static_cast<int>(m_firstBorder_v);
1331 int du, dv;
1332 float dS, dMu, dMv, dMuv, dMu2, dMv2;
1333 m00 = 0.0;
1334 m10 = 0.0;
1335 m01 = 0.0;
1336 m11 = 0.0;
1337 m20 = 0.0;
1338 m02 = 0.0;
1339 // while we didn't come back to the first point, follow the border
1340 do {
1341 // if it was asked, show the border
1342 if (m_graphics) {
1343 for (int t = 0; t < static_cast<int>(m_thickness); ++t) {
1344 ip.set_u(border_u + t);
1345 ip.set_v(border_v);
1346
1348 }
1349 }
1350#ifdef DEBUG
1351 vpDisplay::displayPoint(I, border_v, border_u, vpColor::red);
1353#endif
1354 // Determine the increments for the parameters
1355 computeFreemanParameters(border_u, border_v, dir, du, dv,
1356 dS, // surface
1357 dMu, dMv, // first order moments
1358 dMuv, dMu2, dMv2); // second order moment
1359
1360 // Update the parameters
1361 border_u += du; // Next position on the border
1362 border_v += dv;
1363 m00 += dS; // enclosed area
1364 m10 += dMu; // First order moment along v axis
1365 m01 += dMv; // First order moment along u axis
1366 if (m_compute_moment) {
1367 m11 += dMuv; // Second order moment
1368 m20 += dMu2; // Second order moment along v axis
1369 m02 += dMv2; // Second order moment along u axis
1370 }
1371 // if we are now out of the image, return an error tracking
1372 if (!isInArea(static_cast<unsigned int>(border_u), static_cast<unsigned int>(border_v))) {
1373 // Can Occur on a single pixel dot located on the top border
1374 return false;
1375 }
1376
1377 // store the new direction and dot border coordinates.
1378
1379 m_direction_list.push_back(dir);
1380
1381 ip.set_u(border_u);
1382 ip.set_v(border_v);
1383 m_ip_edges_list.push_back(ip);
1384
1385 // update the extreme point of the dot.
1386 if (border_v < m_bbox_v_min) {
1387 m_bbox_v_min = border_v;
1388 }
1389 if (border_v > m_bbox_v_max) {
1390 m_bbox_v_max = border_v;
1391 }
1392 if (border_u < m_bbox_u_min) {
1393 m_bbox_u_min = border_u;
1394 }
1395 if (border_u > m_bbox_u_max) {
1396 m_bbox_u_max = border_u;
1397 }
1398
1399 // move around the tracked entity by following the border.
1400 if (computeFreemanChainElement(I, static_cast<unsigned int>(border_u), static_cast<unsigned int>(border_v), dir) == false) {
1401 return false;
1402 }
1403 } while (((getFirstBorder_u() != static_cast<unsigned int>(border_u)) || (getFirstBorder_v() != static_cast<unsigned int>(border_v)) ||
1404 (firstDir != dir)) &&
1405 isInArea(static_cast<unsigned int>(border_u), static_cast<unsigned int>(border_v)));
1406
1407#ifdef VP_DEBUG
1408#if VP_DEBUG_MODE == 3
1410#endif
1411#endif
1412
1413 // if the surface is one or zero , the center of gravity wasn't properly
1414 // detected. Return an error tracking.
1415 // if( m00 == 0 || m00 == 1 )
1416 if ((std::fabs(m00) <= std::numeric_limits<double>::epsilon()) ||
1417 (std::fabs(m00 - 1.) <= (vpMath::maximum(std::fabs(m00), 1.) * std::numeric_limits<double>::epsilon()))) {
1418 return false;
1419 }
1420 else // compute the center
1421 {
1422 // this magic formula gives the coordinates of the center of gravity
1423 double tmpCenter_u = m10 / m00;
1424 double tmpCenter_v = m01 / m00;
1425
1426 // Updates the second order centered moments
1427 if (m_compute_moment) {
1428 mu11 = m11 - (tmpCenter_u * m01);
1429 mu02 = m02 - (tmpCenter_v * m01);
1430 mu20 = m20 - (tmpCenter_u * m10);
1431 }
1432
1433 m_cog.set_u(tmpCenter_u);
1434 m_cog.set_v(tmpCenter_v);
1435 }
1436
1437 m_width = (m_bbox_u_max - m_bbox_u_min) + 1;
1438 m_height = (m_bbox_v_max - m_bbox_v_min) + 1;
1439 m_surface = m00;
1440
1441 computeMeanGrayLevel(I);
1442 return true;
1443}
1444
1460bool vpDot2::findFirstBorder(const vpImage<unsigned char> &I, const unsigned int &u, const unsigned int &v,
1461 unsigned int &border_u, unsigned int &border_v)
1462{
1463 // find the border
1464
1465 // NOTE:
1466 // from here we use int and not double. This is because we don't have
1467 // rounding problems and it's actually more a trouble than something else to
1468 // work with double when navigating around the dot.
1469 border_u = u;
1470 border_v = v;
1471 double epsilon = 0.001;
1472
1473#ifdef DEBUG
1474 std::cout << "gray level: " << m_gray_level_min << " " << m_gray_level_max << std::endl;
1475#endif
1476 while (hasGoodLevel(I, border_u + 1, border_v) && (border_u < m_area.getRight()) /*I.getWidth()*/) {
1477 // if the width of this dot was initialised and we already crossed the dot
1478 // on more than the max possible width, no need to continue, return an
1479 // error tracking
1480 if ((getWidth() > 0) && ((border_u - u) > ((getWidth() / getMaxSizeSearchDistPrecision()) + epsilon))) {
1481 return false;
1482 }
1483#ifdef DEBUG
1484 vpDisplay::displayPoint(I, static_cast<int>(border_v), static_cast<int>(border_u) + 1, vpColor::green);
1486#endif
1487
1488 ++border_u;
1489 }
1490 return true;
1491}
1492
1504bool vpDot2::isInImage(const vpImage<unsigned char> &I) const { return isInImage(I, m_cog); }
1505
1517bool vpDot2::isInImage(const vpImage<unsigned char> &I, const vpImagePoint &ip) const
1518{
1519 unsigned int h = I.getHeight();
1520 unsigned int w = I.getWidth();
1521 double u = ip.get_u();
1522 double v = ip.get_v();
1523
1524 if ((u < 0) || (u >= w)) {
1525 return false;
1526 }
1527 if ((v < 0) || (v >= h)) {
1528 return false;
1529 }
1530 return true;
1531}
1532
1544bool vpDot2::isInArea(const unsigned int &u, const unsigned int &v) const
1545{
1546 unsigned int area_u_min = static_cast<unsigned int>(m_area.getLeft());
1547 unsigned int area_u_max = static_cast<unsigned int>(m_area.getRight());
1548 unsigned int area_v_min = static_cast<unsigned int>(m_area.getTop());
1549 unsigned int area_v_max = static_cast<unsigned int>(m_area.getBottom());
1550
1551 if ((u < area_u_min) || (u > area_u_max)) {
1552 return false;
1553 }
1554 if ((v < area_v_min) || (v > area_v_max)) {
1555 return false;
1556 }
1557 return true;
1558}
1559
1568void vpDot2::getGridSize(unsigned int &gridWidth, unsigned int &gridHeight)
1569{
1570 // first get the research grid width and height Note that
1571 // 1/sqrt(2)=cos(pi/4). The grid squares should be small enough to be
1572 // contained in the dot. We gent this here if the dot is a perfect disc.
1573 // More accurate criterium to define the grid should be implemented if
1574 // necessary
1575 gridWidth = static_cast<unsigned int>((getWidth() * getMaxSizeSearchDistPrecision()) / sqrt(2.));
1576 gridHeight = static_cast<unsigned int>((getHeight() * getMaxSizeSearchDistPrecision()) / sqrt(2.0));
1577
1578 if (gridWidth == 0) {
1579 gridWidth = 1;
1580 }
1581 if (gridHeight == 0) {
1582 gridHeight = 1;
1583 }
1584}
1585
1595void vpDot2::computeMeanGrayLevel(const vpImage<unsigned char> &I)
1596{
1597 int cog_u = static_cast<int>(m_cog.get_u());
1598 int cog_v = static_cast<int>(m_cog.get_v());
1599
1600 unsigned int sum_value = 0;
1601 unsigned int nb_pixels = 0;
1602
1603 for (unsigned int i = static_cast<unsigned int>(m_bbox_u_min); i <= static_cast<unsigned int>(m_bbox_u_max); ++i) {
1604 unsigned int pixel_gray = static_cast<unsigned int>(I[static_cast<unsigned int>(cog_v)][i]);
1605 if ((pixel_gray >= getGrayLevelMin()) && (pixel_gray <= getGrayLevelMax())) {
1606 sum_value += pixel_gray;
1607 ++nb_pixels;
1608 }
1609 }
1610 for (unsigned int i = static_cast<unsigned int>(m_bbox_v_min); i <= static_cast<unsigned int>(m_bbox_v_max); ++i) {
1611 unsigned char pixel_gray = I[i][static_cast<unsigned int>(cog_u)];
1612 if ((pixel_gray >= getGrayLevelMin()) && (pixel_gray <= getGrayLevelMax())) {
1613 sum_value += pixel_gray;
1614 ++nb_pixels;
1615 }
1616 }
1617 const unsigned int nb_min_pixels = 10;
1618 if (nb_pixels < nb_min_pixels) { // could be good to choose the min nb points from area of dot
1619 // add diagonals points to have enough point
1620 int imin, imax;
1621 if ((cog_u - m_bbox_u_min) >(cog_v - m_bbox_v_min)) {
1622 imin = cog_v - m_bbox_v_min;
1623 }
1624 else {
1625 imin = cog_u - m_bbox_u_min;
1626 }
1627 if ((m_bbox_u_max - cog_u) > (m_bbox_v_max - cog_v)) {
1628 imax = m_bbox_v_max - cog_v;
1629 }
1630 else {
1631 imax = m_bbox_u_max - cog_u;
1632 }
1633 for (int i = -imin; i <= imax; ++i) {
1634 unsigned int pixel_gray = static_cast<unsigned int>(I[static_cast<unsigned int>(cog_v + i)][static_cast<unsigned int>(cog_u + i)]);
1635 if ((pixel_gray >= getGrayLevelMin()) && (pixel_gray <= getGrayLevelMax())) {
1636 sum_value += pixel_gray;
1637 ++nb_pixels;
1638 }
1639 }
1640
1641 if ((cog_u - m_bbox_u_min) > (m_bbox_v_max - cog_v)) {
1642 imin = m_bbox_v_max - cog_v;
1643 }
1644 else {
1645 imin = cog_u - m_bbox_u_min;
1646 }
1647 if ((m_bbox_u_max - cog_u) > (cog_v - m_bbox_v_min)) {
1648 imax = cog_v - m_bbox_v_min;
1649 }
1650 else {
1651 imax = m_bbox_u_max - cog_u;
1652 }
1653
1654 for (int i = -imin; i <= imax; ++i) {
1655 unsigned char pixel_gray = I[static_cast<unsigned int>(cog_v - i)][static_cast<unsigned int>(cog_u + i)];
1656 if ((pixel_gray >= getGrayLevelMin()) && (pixel_gray <= getGrayLevelMax())) {
1657 sum_value += pixel_gray;
1658 ++nb_pixels;
1659 }
1660 }
1661 }
1662
1663 if (nb_pixels == 0) {
1664 // should never happen
1665 throw(vpTrackingException(vpTrackingException::notEnoughPointError, "No point was found"));
1666 }
1667 else {
1668 m_mean_gray_level = sum_value / nb_pixels;
1669 }
1670}
1671
1690vpMatrix vpDot2::defineDots(vpDot2 dot[], const unsigned int &n, const std::string &dotFile, vpImage<unsigned char> &I,
1691 vpColor col, bool trackDot)
1692{
1693 vpMatrix Cogs(n, 2);
1694 vpImagePoint cog;
1695 unsigned int i;
1696 bool fromFile = vpIoTools::checkFilename(dotFile.c_str());
1697 if (fromFile) {
1698 vpMatrix::loadMatrix(dotFile, Cogs);
1699 std::cout << Cogs.getRows() << " dots loaded from file " << dotFile << std::endl;
1700 }
1701
1702 // test number of cogs in file
1703 if (Cogs.getRows() < n) {
1704 std::cout << "Dot file has a wrong number of dots : redefining them" << std::endl;
1705 fromFile = false;
1706 }
1707
1708 // read from file and tracks the dots
1709 if (fromFile) {
1710 try {
1711 const unsigned int cross_size = 10;
1712 for (i = 0; i < n; ++i) {
1713 cog.set_uv(Cogs[i][0], Cogs[i][1]);
1714 dot[i].setGraphics(true);
1715 dot[i].setCog(cog);
1716 if (trackDot) {
1717 dot[i].initTracking(I, cog);
1718 dot[i].track(I);
1719 vpDisplay::displayCross(I, cog, cross_size, col);
1720 }
1721 }
1722 }
1723 catch (...) {
1724 std::cout << "Cannot track dots from file" << std::endl;
1725 fromFile = false;
1726 }
1728
1729 // check that dots are far away ones from the other
1730 i = 0;
1731 while ((i < n) && fromFile) {
1732 double d = sqrt(vpMath::sqr(dot[i].getHeight()) + vpMath::sqr(dot[i].getWidth()));
1733 unsigned int j = 0;
1734 while ((j < n) && fromFile) {
1735 if (j != i) {
1736 if (dot[i].getDistance(dot[j]) < d) {
1737 fromFile = false;
1738 std::cout << "Dots from file seem incoherent" << std::endl;
1739 }
1740 }
1741 ++j;
1742 }
1743 ++i;
1744 }
1745 }
1746
1747 if (!fromFile) {
1750
1751 std::cout << "Click on the " << n << " dots clockwise starting from upper/left dot..." << std::endl;
1752 const unsigned int cross_size = 10;
1753 for (i = 0; i < n; ++i) {
1754 if (trackDot) {
1755 dot[i].setGraphics(true);
1756 dot[i].initTracking(I);
1757 cog = dot[i].getCog();
1758 }
1759 else {
1760 vpDisplay::getClick(I, cog);
1761 dot[i].setCog(cog);
1762 }
1763 Cogs[i][0] = cog.get_u();
1764 Cogs[i][1] = cog.get_v();
1765 vpDisplay::displayCross(I, cog, cross_size, col);
1767 }
1768 }
1769
1770 if ((!fromFile) && (dotFile != "")) {
1771 vpMatrix::saveMatrix(dotFile, Cogs);
1772 std::cout << Cogs.getRows() << " dots written to file " << dotFile << std::endl;
1773 }
1774
1775 // back to non graphic mode
1776 for (i = 0; i < n; ++i) {
1777 dot[i].setGraphics(false);
1778 }
1779
1780 return Cogs;
1781}
1782
1799void vpDot2::trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage<unsigned char> &I,
1800 std::vector<vpImagePoint> &cogs, vpImagePoint *cogStar)
1801{
1802 // tracking
1803 for (unsigned int i = 0; i < n; ++i) {
1804 dot[i].track(I);
1805 cogs.push_back(dot[i].getCog());
1806 }
1807 // trajectories
1808 unsigned int cogs_size = static_cast<unsigned int>(cogs.size());
1809 for (unsigned int i = n; i < cogs_size; ++i) {
1810 const unsigned int circle_size = 4;
1811 vpDisplay::displayCircle(I, cogs[i], circle_size, vpColor::green, true);
1812 }
1813 // initial position
1814 for (unsigned int i = 0; i < n; ++i) {
1815 const unsigned int circle_size = 4;
1816 vpDisplay::displayCircle(I, cogs[i], circle_size, vpColor::blue, true);
1817 }
1818 // if exists, desired position
1819 if (cogStar != nullptr) {
1820 const unsigned int circle_size = 10;
1821 for (unsigned int i = 0; i < n; ++i) {
1822 vpDisplay::displayDotLine(I, cogStar[i], dot[i].getCog(), vpColor::red);
1823 vpDisplay::displayCircle(I, cogStar[i], circle_size, vpColor::red, true);
1824 }
1825 }
1827}
1828
1844 const std::list<vpImagePoint> &edges_list, vpColor color, unsigned int thickness)
1845{
1846 const unsigned int val_3 = 3;
1847 const unsigned int val_8 = 8;
1848
1849 vpDisplay::displayCross(I, cog, (val_3 * thickness) + val_8, color, thickness);
1850 std::list<vpImagePoint>::const_iterator it;
1851
1852 std::list<vpImagePoint>::const_iterator edges_list_end = edges_list.end();
1853 for (it = edges_list.begin(); it != edges_list_end; ++it) {
1854 vpDisplay::displayPoint(I, *it, color);
1855 }
1856}
1857
1872void vpDot2::display(const vpImage<vpRGBa> &I, const vpImagePoint &cog, const std::list<vpImagePoint> &edges_list,
1873 vpColor color, unsigned int thickness)
1874{
1875 const unsigned int val_3 = 3;
1876 const unsigned int val_8 = 8;
1877 vpDisplay::displayCross(I, cog, (val_3 * thickness) + val_8, color, thickness);
1878 std::list<vpImagePoint>::const_iterator it;
1879 std::list<vpImagePoint>::const_iterator edges_list_end = edges_list.end();
1880 for (it = edges_list.begin(); it != edges_list_end; ++it) {
1881 vpDisplay::displayPoint(I, *it, color);
1882 }
1883}
1884
1890VISP_EXPORT std::ostream &operator<<(std::ostream &os, vpDot2 &d) { return (os << "(" << d.getCog() << ")"); }
1891
1892END_VISP_NAMESPACE
unsigned int getRows() const
Definition vpArray2D.h:433
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
static const vpColor red
Definition vpColor.h:198
static const vpColor blue
Definition vpColor.h:204
static const vpColor purple
Definition vpColor.h:209
static const vpColor green
Definition vpColor.h:201
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)
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:221
friend VISP_EXPORT std::ostream & operator<<(std::ostream &os, vpDot2 &d)
Definition vpDot2.cpp:1890
vpDot2()
Definition vpDot2.cpp:109
unsigned int getGrayLevelMax() const
Definition vpDot2.h:227
void track(const vpImage< unsigned char > &I, bool canMakeTheWindowGrow=true)
Definition vpDot2.cpp:441
double m02
Definition vpDot2.h:434
double m01
Definition vpDot2.h:410
void setGraphics(bool activate)
Definition vpDot2.h:320
double mu11
Definition vpDot2.h:443
vpDot2 & operator=(const vpDot2 &twinDot)
Definition vpDot2.cpp:164
static void trackAndDisplay(vpDot2 dot[], const unsigned int &n, vpImage< unsigned char > &I, std::vector< vpImagePoint > &cogs, vpImagePoint *cogStar=nullptr)
Definition vpDot2.cpp:1799
double getEllipsoidShapePrecision() const
Definition vpDot2.cpp:640
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)
void setMaxSizeSearchDistPrecision(const double &maxSizeSearchDistancePrecision)
Definition vpDot2.cpp:819
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1) const
Definition vpDot2.cpp:219
double m20
Definition vpDot2.h:425
double m00
Definition vpDot2.h:394
double getArea() const
Definition vpDot2.cpp:617
void setSizePrecision(const double &sizePrecision)
Definition vpDot2.cpp:745
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition vpDot2.cpp:715
double m11
Definition vpDot2.h:418
void setHeight(const double &height)
Definition vpDot2.cpp:684
double getMaxSizeSearchDistPrecision() const
Definition vpDot2.cpp:648
void setCog(const vpImagePoint &ip)
Definition vpDot2.h:263
vpImagePoint getCog() const
Definition vpDot2.h:183
double m10
Definition vpDot2.h:402
double getSizePrecision() const
Definition vpDot2.cpp:631
double getGrayLevelPrecision() const
Definition vpDot2.cpp:624
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition vpDot2.h:292
double getDistance(const vpDot2 &distantDot) const
Definition vpDot2.cpp:653
double mu02
Definition vpDot2.h:453
void setWidth(const double &width)
Definition vpDot2.cpp:672
double mu20
Definition vpDot2.h:448
double getWidth() const
Definition vpDot2.cpp:603
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition vpDot2.cpp:790
double getMeanGrayLevel() const
Definition vpDot2.h:236
void setArea(const double &area)
Definition vpDot2.cpp:696
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition vpDot2.cpp:263
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:1690
double getHeight() const
Definition vpDot2.cpp:610
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double get_u() const
void set_u(double u)
void set_uv(double u, double v)
void set_v(double v)
double get_v() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:181
static bool checkFilename(const std::string &filename)
static Type maximum(const Type &a, const Type &b)
Definition vpMath.h:257
static double sqr(double x)
Definition vpMath.h:203
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
static bool loadMatrix(const std::string &filename, vpArray2D< double > &M, bool binary=false, char *header=nullptr)
Definition vpMatrix.h:841
static bool saveMatrix(const std::string &filename, const vpArray2D< double > &M, bool binary=false, const char *header="")
Definition vpMatrix.h:997
Defines a rectangle in the plane.
Definition vpRect.h:79
void init()
Default initialization.
Definition vpTracker.cpp:43
vpTracker()
Default constructor.
Definition vpTracker.cpp:45
Error that can be emitted by the vpTracker class and its derivatives.
@ featureLostError
Tracker lost feature.
@ notEnoughPointError
Not enough point to track.