Visual Servoing Platform  version 3.6.1 under development (2024-09-07)
vpDot2_search.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 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  * Search a dot in an area.
32  */
33 
34 #include <visp3/core/vpConfig.h>
35 #include <visp3/core/vpDisplay.h>
36 #include <visp3/blob/vpDot2.h>
37 
39 
45  void vpDot2::searchDotsAreaGoodGerm(vpSearchDotsInAreaGoodGermData &data)
46 {
47 // Compute the right border position for this possible germ
48  unsigned int border_u;
49  unsigned int border_v;
50  bool good_germ = true;
51  std::list<vpDot2>::iterator itbad;
52  std::list<vpDot2>::iterator itnice;
53  vpDot2 *dotToTest = nullptr;
54  vpDot2 tmpDot;
55  vpImagePoint cogTmpDot;
56  if (findFirstBorder(data.m_I, data.m_u, data.m_v, border_u, border_v) == false) {
57  // germ is not good.
58  // Jump all the pixels between v,u and v,
59  // dotToTest->getFirstBorder_u()
60  data.m_u = border_u;
61  data.m_v = border_v;
62  }
63  else {
64  itbad = data.m_badDotsVector.begin();
65  vpImagePoint cogBadDot;
66 
67  while ((itbad != data.m_badDotsVector.end()) && (good_germ == true)) {
68  if ((static_cast<double>(data.m_u) >= (*itbad).m_bbox_u_min) && (static_cast<double>(data.m_u) <= (*itbad).m_bbox_u_max) &&
69  (static_cast<double>(data.m_v) >= (*itbad).m_bbox_v_min) && (static_cast<double>(data.m_v) <= (*itbad).m_bbox_v_max)) {
70  std::list<vpImagePoint>::const_iterator it_edges = m_ip_edges_list.begin();
71  while ((it_edges != m_ip_edges_list.end()) && (good_germ == true)) {
72  // Test if the germ belong to a previously detected dot:
73  // - from the germ go right to the border and compare this
74  // position to the list of pixels of previously detected dots
75  cogBadDot = *it_edges;
76  if ((std::fabs(border_u - cogBadDot.get_u()) <=
77  (vpMath::maximum(std::fabs(static_cast<double>(border_u)), std::fabs(cogBadDot.get_u())) *
78  std::numeric_limits<double>::epsilon())) &&
79  (std::fabs(data.m_v - cogBadDot.get_v()) <=
80  (vpMath::maximum(std::fabs(static_cast<double>(data.m_v)), std::fabs(cogBadDot.get_v())) *
81  std::numeric_limits<double>::epsilon()))) {
82  good_germ = false;
83  }
84  ++it_edges;
85  }
86  }
87  ++itbad;
88  }
89 
90  if (!good_germ) {
91  // Jump all the pixels between v,u and v,
92  // dotToTest->getFirstBorder_u()
93  data.m_u = border_u;
94  data.m_v = border_v;
95  }
96  else {
97  vpImagePoint germ;
98  germ.set_u(data.m_u);
99  germ.set_v(data.m_v);
100 
101  // otherwise estimate the width, height and surface of the dot we
102  // created, and test it.
103  if (dotToTest != nullptr) {
104  delete dotToTest;
105  }
106  dotToTest = getInstance();
107  dotToTest->setCog(germ);
108  dotToTest->setGrayLevelMin(getGrayLevelMin());
109  dotToTest->setGrayLevelMax(getGrayLevelMax());
111  dotToTest->setSizePrecision(getSizePrecision());
112  dotToTest->setGraphics(m_graphics);
113  dotToTest->setGraphicsThickness(m_thickness);
114  dotToTest->setComputeMoments(true);
115  dotToTest->setArea(m_area);
116  dotToTest->setEllipsoidShapePrecision(m_ellipsoidShapePrecision);
117  dotToTest->setEllipsoidBadPointsPercentage(m_allowedBadPointsPercentage);
118 
119  // first compute the parameters of the dot.
120  // if for some reasons this caused an error tracking
121  // (dot partially out of the image...), check the next intersection
122  if (dotToTest->computeParameters(data.m_I) == false) {
123  // Jump all the pixels between v,u and v,
124  // dotToTest->getFirstBorder_u()
125  data.m_u = border_u;
126  data.m_v = border_v;
127  }
128  else {
129  // if the dot to test is valid,
130  if (dotToTest->isValid(data.m_I, *this)) {
131  vpImagePoint cogDotToTest = dotToTest->getCog();
132  // Compute the distance to the center. The center used here is not the
133  // area center available by area.getCenter(area_center_u,
134  // area_center_v) but the center of the input area which may be
135  // partially outside the image.
136 
137  double area_center_u = (data.m_area.getLeft() + (data.m_area.getWidth() / 2.0)) - 0.5;
138  double area_center_v = (data.m_area.getTop() + (data.m_area.getHeight() / 2.0)) - 0.5;
139 
140  double thisDiff_u = cogDotToTest.get_u() - area_center_u;
141  double thisDiff_v = cogDotToTest.get_v() - area_center_v;
142  double thisDist = sqrt((thisDiff_u * thisDiff_u) + (thisDiff_v * thisDiff_v));
143 
144  bool stopLoop = false;
145  itnice = data.m_niceDots.begin();
146 
147  while ((itnice != data.m_niceDots.end()) && (stopLoop == false)) {
148  tmpDot = *itnice;
149 
150  // --comment: epsilon equals 0.001 -- detecte +sieurs points
151  double epsilon = 3.0;
152  // if the center of the dot is the same than the current
153  // don't add it, test the next point of the grid
154  cogTmpDot = tmpDot.getCog();
155 
156  if ((fabs(cogTmpDot.get_u() - cogDotToTest.get_u()) < epsilon) &&
157  (fabs(cogTmpDot.get_v() - cogDotToTest.get_v()) < epsilon)) {
158  stopLoop = true;
159  // Jump all the pixels between v,u and v,
160  // tmpDot->getFirstBorder_u()
161  data.m_u = border_u;
162  data.m_v = border_v;
163  }
164  else {
165  double otherDiff_u = cogTmpDot.get_u() - area_center_u;
166  double otherDiff_v = cogTmpDot.get_v() - area_center_v;
167  double otherDist = sqrt((otherDiff_u * otherDiff_u) + (otherDiff_v * otherDiff_v));
168 
169  // if the distance of the curent vector element to the center
170  // is greater than the distance of this dot to the center,
171  // then add this dot before the current vector element.
172  if (otherDist > thisDist) {
173  data.m_niceDots.insert(itnice, *dotToTest);
174  stopLoop = true;
175  // Jump all the pixels between v,u and v,
176  // tmpDot->getFirstBorder_u()
177  data.m_u = border_u;
178  data.m_v = border_v;
179  }
180  ++itnice;
181  }
182  }
183 
184  // if we reached the end of the vector without finding the dot
185  // or inserting it, insert it now.
186  if ((itnice == data.m_niceDots.end()) && (stopLoop == false)) {
187  data.m_niceDots.push_back(*dotToTest);
188  }
189  }
190  else {
191  // Store bad dots
192  data.m_badDotsVector.push_front(*dotToTest);
193  }
194  }
195  }
196  }
197  if (dotToTest != nullptr) {
198  delete dotToTest;
199  }
200 }
201 
224 void vpDot2::searchDotsInArea(const vpImage<unsigned char> &I, int area_u, int area_v, unsigned int area_w,
225  unsigned int area_h, std::list<vpDot2> &niceDots)
226 
227 {
228  // clear the list of nice dots
229  niceDots.clear();
230 
231  // Fit the input area in the image; we keep only the common part between
232  // this area and the image.
233  setArea(I, area_u, area_v, area_w, area_h);
234 
235  // compute the size of the search grid
236  unsigned int gridWidth;
237  unsigned int gridHeight;
238  getGridSize(gridWidth, gridHeight);
239 
240  if (m_graphics) {
241  // Display the area were the dot is search
242  vpDisplay::displayRectangle(I, m_area, vpColor::blue, false, m_thickness);
243  }
244 
245 #ifdef DEBUG
247  vpDisplay::flush(I);
248 #endif
249  // start the search loop; for all points of the search grid,
250  // test if the pixel belongs to a valid dot.
251  // if it is so eventually add it to the vector of valid dots.
252  std::list<vpDot2> badDotsVector;
253  std::list<vpDot2>::iterator itnice;
254 
255  vpDot2 tmpDot;
256 
257  unsigned int area_u_min = static_cast<unsigned int>(m_area.getLeft());
258  unsigned int area_u_max = static_cast<unsigned int>(m_area.getRight());
259  unsigned int area_v_min = static_cast<unsigned int>(m_area.getTop());
260  unsigned int area_v_max = static_cast<unsigned int>(m_area.getBottom());
261 
262  unsigned int u, v;
263  vpImagePoint cogTmpDot;
264 
265  v = area_v_min;
266  while (v < area_v_max) {
267  u = area_u_min;
268  while (u < area_u_max) {
269  // if the pixel we're in doesn't have the right color (outside the
270  // graylevel interval), no need to check further, just get to the
271  // next grid intersection.
272  if (hasGoodLevel(I, u, v)) {
273 
274  // Test if an other germ is inside the bounding box of a dot previously
275  // detected
276  bool good_germ = true;
277 
278  itnice = niceDots.begin();
279  while ((itnice != niceDots.end()) && (good_germ == true)) {
280  tmpDot = *itnice;
281 
282  cogTmpDot = tmpDot.getCog();
283  double u0 = cogTmpDot.get_u();
284  double v0 = cogTmpDot.get_v();
285  double half_w = tmpDot.getWidth() / 2.;
286  double half_h = tmpDot.getHeight() / 2.;
287 
288  if ((u >= (u0 - half_w)) && (u <= (u0 + half_w)) && (v >= (v0 - half_h)) && (v <= (v0 + half_h))) {
289  // Germ is in a previously detected dot
290  good_germ = false;
291  }
292  ++itnice;
293  }
294 
295  if (good_germ) {
296  vpRect area(area_u, area_v, area_w, area_h);
297  vpSearchDotsInAreaGoodGermData data(I, area, u, v, niceDots, badDotsVector);
298  searchDotsAreaGoodGerm(data);
299  }
300  }
301  u = u + gridWidth;
302  }
303  v = v + gridHeight;
304  }
305 }
306 
307 END_VISP_NAMESPACE
static const vpColor blue
Definition: vpColor.h:223
static void flush(const vpImage< unsigned char > &I)
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:125
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:219
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:225
void setGraphics(bool activate)
Definition: vpDot2.h:318
void setGraphicsThickness(unsigned int thickness)
Definition: vpDot2.h:326
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 setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:357
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:756
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:726
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:338
void setCog(const vpImagePoint &ip)
Definition: vpDot2.h:261
vpImagePoint getCog() const
Definition: vpDot2.h:181
double getSizePrecision() const
Definition: vpDot2.cpp:642
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:635
void setEllipsoidBadPointsPercentage(const double &percentage=0.0)
Definition: vpDot2.h:290
double getWidth() const
Definition: vpDot2.cpp:614
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:801
void setArea(const double &area)
Definition: vpDot2.cpp:707
void setComputeMoments(bool activate)
Definition: vpDot2.h:276
double getHeight() const
Definition: vpDot2.cpp:621
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_u() const
Definition: vpImagePoint.h:136
void set_u(double u)
Definition: vpImagePoint.h:335
void set_v(double v)
Definition: vpImagePoint.h:346
double get_v() const
Definition: vpImagePoint.h:147
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:254
Defines a rectangle in the plane.
Definition: vpRect.h:79
double getLeft() const
Definition: vpRect.h:173
double getRight() const
Definition: vpRect.h:179
double getBottom() const
Definition: vpRect.h:97
double getTop() const
Definition: vpRect.h:192