1 /**************************************************************************** 2 * 3 * ViSP, open source Visual Servoing Platform software. 4 * Copyright (C) 2005 - 2019 by Inria. All rights reserved. 5 * 6 * This software is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * See the file LICENSE.txt at the root directory of this source 11 * distribution for additional information about the GNU GPL. 12 * 13 * For using ViSP with software that can not be combined with the GNU 14 * GPL, please contact Inria about acquiring a ViSP Professional 15 * Edition License. 16 * 17 * See http://visp.inria.fr for more information. 18 * 19 * This software was developed at: 20 * Inria Rennes - Bretagne Atlantique 21 * Campus Universitaire de Beaulieu 22 * 35042 Rennes Cedex 23 * France 24 * 25 * If you have questions regarding the use of this file, please contact 26 * Inria at visp@inria.fr 27 * 28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 30 * 31 * Description: 32 * Track a white dot. 33 * 34 * Authors: 35 * Eric Marchand 36 * Fabien Spindler 37 * 38 *****************************************************************************/ 39 40 /*! 41 \file vpDot.h 42 \brief Track a white dot 43 */ 44 45 #ifndef vpDot_hh 46 #define vpDot_hh 47 48 #include <visp3/core/vpConfig.h> 49 #include <visp3/core/vpDisplay.h> 50 #include <visp3/core/vpImage.h> 51 #include <visp3/core/vpImagePoint.h> 52 #include <visp3/core/vpPolygon.h> 53 #include <visp3/core/vpRect.h> 54 #include <visp3/core/vpTracker.h> 55 56 #include <fstream> 57 #include <list> 58 #include <math.h> 59 #include <vector> 60 61 #ifdef VISP_USE_MSVC 62 #pragma comment(linker, "/STACK:256000000") // Increase max recursion depth 63 #endif 64 65 /*! 66 \class vpDot 67 68 \ingroup module_blob 69 70 \brief This tracker is meant to track a dot (connected pixels with same 71 gray level) on a vpImage. 72 73 The underground algorithm is based on a binarization of the image 74 and a connex component segmentation to determine the dot 75 characteristics (location, moments, size...). 76 77 The following sample code shows how to grab images from a firewire camera, 78 track a blob and display the tracking results. 79 80 \code 81 #include <visp3/blob/vpDot.h> 82 #include <visp3/gui/vpDisplayX.h> 83 #include <visp3/sensor/vp1394TwoGrabber.h> 84 85 int main() 86 { 87 #if defined(VISP_HAVE_DC1394) 88 vpImage<unsigned char> I; // Create a gray level image container 89 vp1394TwoGrabber g(false); // Create a grabber based on libdc1394-2.x third party lib 90 g.acquire(I); // Acquire an image 91 92 #if defined(VISP_HAVE_X11) 93 vpDisplayX d(I, 0, 0, "Camera view"); 94 #endif 95 vpDisplay::display(I); 96 vpDisplay::flush(I); 97 98 vpDot blob; 99 blob.initTracking(I); 100 blob.setGraphics(true); 101 102 while(1) { 103 g.acquire(I); // Acquire an image 104 vpDisplay::display(I); 105 blob.track(I); 106 107 vpDisplay::flush(I); 108 } 109 #endif 110 } 111 \endcode 112 113 \sa vpDot2 114 */ 115 class VISP_EXPORT vpDot : public vpTracker 116 { 117 public: 118 /*! \enum vpConnexityType 119 Type of connexity 4, or 8. 120 */ 121 typedef enum { 122 CONNEXITY_4, /*!< For a given pixel 4 neighbors are considered (left, 123 right, up, down) */ 124 CONNEXITY_8 /*!< For a given pixel 8 neighbors are considered (left, 125 right, up, down, and the 4 pixels located on the diagonal) */ 126 } vpConnexityType; 127 128 #ifdef VISP_BUILD_DEPRECATED_FUNCTIONS 129 public: 130 #else 131 private: 132 #endif 133 static const unsigned int SPIRAL_SEARCH_SIZE; /*!< Spiral size for the dot search. */ 134 135 double m00; /*!< Considering the general distribution moments for \f$ N \f$ 136 points defined by the relation \f$ m_{ij} = \sum_{h=0}^{N} 137 u_h^i v_h^j \f$, \f$ m_{00} \f$ is a zero order moment obtained 138 with \f$i = j = 0 \f$. 139 140 \sa setComputeMoments() 141 */ 142 double m01; /*!< Considering the general distribution moments for \f$ N \f$ 143 points defined by the relation \f$ m_{ij} = \sum_{h=0}^{N} 144 u_h^i v_h^j \f$, \f$ m_{01} \f$ is a first order moment 145 obtained with \f$i = 0 \f$ and \f$ j = 1 \f$. 146 147 \sa setComputeMoments() 148 */ 149 double m10; /*!< Considering the general distribution moments for \f$ N \f$ 150 points defined by the relation \f$ m_{ij} = \sum_{h=0}^{N} 151 u_h^i v_h^j \f$, \f$ m_{10} \f$ is a first order moment 152 obtained with \f$i = 1 \f$ and \f$ j = 0 \f$. 153 154 \sa setComputeMoments() 155 */ 156 double m11; /*!< Considering the general distribution moments for \f$ N \f$ 157 points defined by the relation \f$ m_{ij} = \sum_{h=0}^{N} 158 u_h^i v_h^j \f$, \f$ m_{11} \f$ is a first order moment 159 obtained with \f$i = 1 \f$ and \f$ j = 1 \f$. 160 161 \sa setComputeMoments() 162 */ 163 double m20; /*!< Considering the general distribution moments for \f$ N \f$ 164 points defined by the relation \f$ m_{ij} = \sum_{h=0}^{N} 165 u_h^i v_h^j \f$, \f$ m_{20} \f$ is a second order moment 166 obtained with \f$i = 2 \f$ and \f$ j = 0 \f$. 167 168 \sa setComputeMoments() 169 */ 170 double m02; /*!< Considering the general distribution moments for \f$ N \f$ 171 points defined by the relation \f$ m_{ij} = \sum_{h=0}^{N} 172 u_h^i v_h^j \f$, \f$ m_{02} \f$ is a second order moment 173 obtained with \f$i = 0 \f$ and \f$ j = 2 \f$. 174 175 \sa setComputeMoments() 176 */ 177 double mu11; /*!< \f$ \mu_{11} \f$ is a second order centered moment defined 178 by: \f$ \mu_{11} = m_{11} - \frac{m_{10}}{m_{00}}m_{01} \f$ 179 180 \sa setComputeMoments() 181 */ 182 double mu20; /*!< \f$ \mu_{20} \f$ is a second order centered moment defined 183 by: \f$ \mu_{20} = m_{20} - \frac{m_{10}}{m_{00}}m_{10} \f$ 184 185 \sa setComputeMoments() 186 */ 187 double mu02; /*!< \f$ \mu_{02} \f$ is a second order centered moment defined 188 by: \f$ \mu_{02} = m_{02} - \frac{m_{01}}{m_{00}}m_{01} \f$ 189 190 \sa setComputeMoments() 191 */ 192 193 public: 194 vpDot(); 195 explicit vpDot(const vpImagePoint &ip); 196 vpDot(const vpDot &d); 197 virtual ~vpDot(); 198 199 void display(const vpImage<unsigned char> &I, vpColor color = vpColor::red, unsigned int thickness = 1) const; 200 201 /*! 202 Gets the second order normalized centered moment \f$ n_{ij} \f$ 203 as a 3-dim vector containing \f$ n_{20}, n_{11}, n_{02} \f$ 204 such as \f$ n_{ij} = \mu_{ij}/m_{00} \f$ 205 206 \return The 3-dim vector containing \f$ n_{20}, n_{11}, n_{02} \f$. 207 208 \sa getCog(), getArea() 209 */ get_nij()210 inline vpColVector get_nij() const 211 { 212 vpColVector nij(3); 213 nij[0] = mu20 / m00; 214 nij[1] = mu11 / m00; 215 nij[2] = mu02 / m00; 216 217 return nij; 218 } 219 220 /*! 221 Gets the area of the blob corresponding also to the zero order moment. 222 223 \return The blob area. 224 */ getArea()225 inline double getArea() const { return m00; } 226 227 /*! 228 229 Return the dot bounding box. 230 231 \sa getWidth(), getHeight() 232 233 */ getBBox()234 inline vpRect getBBox() const 235 { 236 vpRect bbox; 237 238 bbox.setRect(this->u_min, this->v_min, this->u_max - this->u_min + 1, this->v_max - this->v_min + 1); 239 240 return (bbox); 241 }; 242 /*! 243 Return the location of the dot center of gravity. 244 245 \return The coordinates of the center of gravity. 246 */ getCog()247 inline vpImagePoint getCog() const { return cog; } 248 249 /*! 250 Return the list of all the image points on the border of the dot. 251 252 \warning Doesn't return the image points inside the dot anymore. To get 253 those points see getConnexities(). 254 */ getEdges()255 inline std::list<vpImagePoint> getEdges() const { return this->ip_edges_list; }; 256 257 /*! 258 259 Return the list of all the image points inside the dot. 260 261 \return The list of all the images points in the dot. 262 This list is updated after a call to track(). 263 264 */ getConnexities()265 inline std::list<vpImagePoint> getConnexities() const { return this->ip_connexities_list; }; 266 getGamma()267 inline double getGamma() const { return this->gamma; }; 268 /*! 269 270 Return the precision of the gray level of the dot. It is a double 271 precision float witch value is in ]0,1]. 1 means full precision, whereas 272 values close to 0 show a very bad precision. 273 274 */ getGrayLevelPrecision()275 double getGrayLevelPrecision() const { return grayLevelPrecision; } getMaxDotSize()276 double getMaxDotSize() const { return this->maxDotSizePercentage; } 277 /*! 278 Return the mean gray level value of the dot. 279 */ getMeanGrayLevel()280 double getMeanGrayLevel() const { return (this->mean_gray_level); }; 281 282 /*! 283 \return a vpPolygon made from the edges of the dot. 284 */ getPolygon()285 vpPolygon getPolygon() const { return (vpPolygon(ip_edges_list)); }; 286 287 /*! 288 289 Return the width of the dot. 290 291 \sa getHeight() 292 293 */ getWidth()294 inline unsigned int getWidth() const { return (this->u_max - this->u_min + 1); }; 295 296 /*! 297 298 Return the width of the dot. 299 300 \sa getHeight() 301 302 */ getHeight()303 inline unsigned int getHeight() const { return (this->v_max - this->v_min + 1); }; 304 305 void initTracking(const vpImage<unsigned char> &I); 306 void initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip); 307 void initTracking(const vpImage<unsigned char> &I, const vpImagePoint &ip, unsigned int gray_level_min, 308 unsigned int gray_level_max); 309 310 vpDot &operator=(const vpDot &d); 311 bool operator==(const vpDot &d) const; 312 bool operator!=(const vpDot &d) const; 313 friend VISP_EXPORT std::ostream &operator<<(std::ostream &os, vpDot &d); 314 print(std::ostream & os)315 void print(std::ostream &os) { os << *this << std::endl; } 316 317 /*! 318 Initialize the dot coordinates with \e ip. 319 */ setCog(const vpImagePoint & ip)320 inline void setCog(const vpImagePoint &ip) { this->cog = ip; } 321 322 /*! 323 324 Activates the dot's moments computation. 325 326 \param activate true, if you want to compute the moments. If false, 327 moments are not computed. 328 329 Computed moment are vpDot::m00, vpDot::m10, vpDot::m01, vpDot::m11, 330 vpDot::m20, vpDot::m02 and second order centered moments vpDot::mu11, 331 vpDot::mu20, vpDot::mu02 computed with respect to the blob centroid. 332 333 The coordinates of the region's centroid (u, v) can be computed from the 334 moments by \f$u=\frac{m10}{m00}\f$ and \f$v=\frac{m01}{m00}\f$. 335 336 */ setComputeMoments(bool activate)337 void setComputeMoments(bool activate) { compute_moment = activate; } 338 339 /*! 340 Set the type of connexity: 4 or 8. 341 */ setConnexity(vpConnexityType type)342 void setConnexity(vpConnexityType type) { this->connexityType = type; }; 343 void setMaxDotSize(double percentage); setGrayLevelMin(const unsigned int & level_min)344 void setGrayLevelMin(const unsigned int &level_min) { this->gray_level_min = level_min; }; setGrayLevelMax(const unsigned int & level_max)345 void setGrayLevelMax(const unsigned int &level_max) { this->gray_level_max = level_max; }; 346 void setGrayLevelPrecision(const double &grayLevelPrecision); 347 348 /*! 349 Activates the display of all the pixels of the dot during the tracking. 350 The default thickness of the overlayed drawings can be modified using 351 setGraphicsThickness(). 352 353 \warning To effectively display the dot graphics a call to 354 vpDisplay::flush() is needed. 355 356 \param activate true to activate the display of dot pixels, false to turn 357 off the display. 358 359 \sa setGraphicsThickness() 360 */ setGraphics(bool activate)361 void setGraphics(bool activate) { graphics = activate; } 362 /*! 363 Modify the default thickness that is set to 1 of the drawings in overlay 364 when setGraphics() is enabled. 365 366 \sa setGraphics() 367 */ setGraphicsThickness(unsigned int t)368 void setGraphicsThickness(unsigned int t) { this->thickness = t; }; 369 370 void track(const vpImage<unsigned char> &I); 371 void track(const vpImage<unsigned char> &I, vpImagePoint &ip); 372 373 private: 374 //! internal use only 375 std::list<vpImagePoint> ip_connexities_list; 376 377 //! List of border points 378 std::list<vpImagePoint> ip_edges_list; 379 380 /*! Type of connexity 381 382 \warning In previous version this variable was called connexity 383 */ 384 vpConnexityType connexityType; 385 386 //! coordinates of the point center of gravity 387 vpImagePoint cog; 388 389 // Bounding box 390 unsigned int u_min, u_max, v_min, v_max; 391 392 // Flag used to allow display 393 bool graphics; 394 395 unsigned int thickness; // Graphics thickness 396 397 double maxDotSizePercentage; 398 unsigned char gray_level_out; 399 400 double mean_gray_level; // Mean gray level of the dot 401 unsigned int gray_level_min; // left threshold for binarisation 402 unsigned int gray_level_max; // right threshold for binarisation 403 double grayLevelPrecision; // precision of the gray level of the dot. 404 // It is a double precision float witch value is in ]0,1]. 405 // 1 means full precision, whereas values close to 0 show a very bad 406 // precision 407 double gamma; 408 //! flag : true moment are computed 409 bool compute_moment; 410 double nbMaxPoint; 411 412 void init(); 413 void setGrayLevelOut(); 414 bool connexe(const vpImage<unsigned char> &I, unsigned int u, unsigned int v, double &mean_value, double &u_cog, 415 double &v_cog, double &n); 416 bool connexe(const vpImage<unsigned char> &I, unsigned int u, unsigned int v, double &mean_value, double &u_cog, 417 double &v_cog, double &n, std::vector<bool> &checkTab); 418 void COG(const vpImage<unsigned char> &I, double &u, double &v); 419 420 // Static Functions 421 public: 422 static void display(const vpImage<unsigned char> &I, const vpImagePoint &cog, 423 const std::list<vpImagePoint> &edges_list, vpColor color = vpColor::red, 424 unsigned int thickness = 1); 425 static void display(const vpImage<vpRGBa> &I, const vpImagePoint &cog, const std::list<vpImagePoint> &edges_list, 426 vpColor color = vpColor::red, unsigned int thickness = 1); 427 }; 428 429 #endif 430