Visual Servoing Platform  version 3.0.0
trackDot2.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
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 http://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  * Example of dot tracking.
32  *
33  * Authors:
34  * Eric Marchand
35  * Fabien Spindler
36  *
37  *****************************************************************************/
44 #include <visp3/core/vpDebug.h>
45 #include <visp3/core/vpConfig.h>
46 
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <sstream>
50 #include <iomanip>
51 
52 #if defined(VISP_HAVE_MODULE_BLOB) && (defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
53 
54 #include <visp3/core/vpImage.h>
55 #include <visp3/io/vpImageIo.h>
56 #include <visp3/core/vpImagePoint.h>
57 #include <visp3/gui/vpDisplayX.h>
58 #include <visp3/gui/vpDisplayGTK.h>
59 #include <visp3/gui/vpDisplayGDI.h>
60 #include <visp3/gui/vpDisplayOpenCV.h>
61 #include <visp3/blob/vpDot2.h>
62 #include <visp3/io/vpParseArgv.h>
63 #include <visp3/core/vpIoTools.h>
64 
65 // List of allowed command line options
66 #define GETOPTARGS "cdf:i:n:p:s:h"
67 
68 //int gsl_warnings_off;
69 
70 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
71  unsigned first, unsigned nimages, unsigned step);
72 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first,
73  unsigned &nimages, unsigned &step, bool &click_allowed, bool &display);
93 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
94  unsigned first, unsigned nimages, unsigned step)
95 {
96  fprintf(stdout, "\n\
97 Test dot tracking using vpDot2 class.\n\
98 \n\
99 SYNOPSIS\n\
100  %s [-i <test image path>] [-p <personal image path>]\n\
101  [-f <first image>] [-n <number of images>] [-s <step>]\n\
102  [-c] [-d] [-h]\n", name);
103 
104  fprintf(stdout, "\n\
105 OPTIONS: Default\n\
106  -i <input image path> %s\n\
107  Set image input path.\n\
108  From this path read images \n\
109  \"ViSP-images/mire-2/image.%%04d.pgm\". These \n\
110  images come from ViSP-images-x.y.z.tar.gz available \n\
111  on the ViSP website.\n\
112  Setting the VISP_INPUT_IMAGE_PATH environment\n\
113  variable produces the same behaviour than using\n\
114  this option.\n\
115  \n\
116  -p <personal image path> %s\n\
117  Specify a personal sequence containing images \n\
118  to process.\n\
119  By image sequence, we mean one file per image.\n\
120  The following image file formats PNM (PGM P5, PPM P6)\n\
121  are supported. The format is selected by analysing \n\
122  the filename extension.\n\
123  Example : \"C:/Temp/ViSP-images/cube/image.%%04d.pgm\"\n\
124  %%04d is for the image numbering.\n\
125  \n\
126  -f <first image> %u\n\
127  First image number of the sequence.\n\
128  \n\
129  -n <number of images> %u\n\
130  Number of images to load from the sequence.\n\
131  \n\
132  -s <step> %u\n\
133  Step between two images.\n\
134 \n\
135  -c\n\
136  Disable the mouse click. Useful to automaze the \n\
137  execution of this program without humain intervention.\n\
138 \n\
139  -d \n\
140  Turn off the display.\n\
141 \n\
142  -h\n\
143  Print the help.\n",
144  ipath.c_str(), ppath.c_str(), first, nimages, step);
145 
146  if (badparam)
147  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
148 }
166 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first,
167  unsigned &nimages, unsigned &step, bool &click_allowed, bool &display)
168 {
169  const char *optarg_;
170  int c;
171  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
172 
173  switch (c) {
174  case 'c': click_allowed = false; break;
175  case 'd': display = false; break;
176  case 'i': ipath = optarg_; break;
177  case 'p': ppath = optarg_; break;
178  case 'f': first = (unsigned) atoi(optarg_); break;
179  case 'n': nimages = (unsigned) atoi(optarg_); break;
180  case 's': step = (unsigned) atoi(optarg_); break;
181  case 'h': usage(argv[0], NULL, ipath, ppath, first, nimages, step);
182  return false; break;
183 
184  default:
185  usage(argv[0], optarg_, ipath, ppath, first, nimages, step);
186  return false; break;
187  }
188  }
189 
190  if ((c == 1) || (c == -1)) {
191  // standalone param or error
192  usage(argv[0], NULL, ipath, ppath, first, nimages, step);
193  std::cerr << "ERROR: " << std::endl;
194  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
195  return false;
196  }
197 
198  return true;
199 }
200 
201 int
202 main(int argc, const char ** argv)
203 {
204  try {
205  std::string env_ipath;
206  std::string opt_ipath;
207  std::string ipath;
208  std::string opt_ppath;
209  std::string dirname;
210  std::string filename;
211  unsigned opt_first = 1;
212  unsigned opt_nimages = 500;
213  unsigned opt_step = 1;
214  bool opt_click_allowed = true;
215  bool opt_display = true;
216 
217  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
218  env_ipath = vpIoTools::getViSPImagesDataPath();
219 
220  // Set the default input path
221  if (! env_ipath.empty())
222  ipath = env_ipath;
223 
224  // Read the command line options
225  if (getOptions(argc, argv, opt_ipath, opt_ppath,opt_first, opt_nimages,
226  opt_step, opt_click_allowed, opt_display) == false) {
227  exit (-1);
228  }
229 
230  // Get the option values
231  if (!opt_ipath.empty())
232  ipath = opt_ipath;
233 
234  // Compare ipath and env_ipath. If they differ, we take into account
235  // the input path comming from the command line option
236  if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
237  if (ipath != env_ipath) {
238  std::cout << std::endl
239  << "WARNING: " << std::endl;
240  std::cout << " Since -i <visp image path=" << ipath << "> "
241  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
242  << " we skip the environment variable." << std::endl;
243  }
244  }
245 
246  // Test if an input path is set
247  if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty() ){
248  usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_nimages, opt_step);
249  std::cerr << std::endl
250  << "ERROR:" << std::endl;
251  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
252  << std::endl
253  << " environment variable to specify the location of the " << std::endl
254  << " image path where test images are located." << std::endl
255  << " Use -p <personal image path> option if you want to "<<std::endl
256  << " use personal images." << std::endl
257  << std::endl;
258 
259  exit(-1);
260  }
261 
262  // Declare an image, this is a gray level image (unsigned char)
263  // it size is not defined yet, it will be defined when the image will
264  // read on the disk
266 
267  unsigned iter = opt_first;
268  std::ostringstream s;
269  char cfilename[FILENAME_MAX];
270 
271  if (opt_ppath.empty()){
272 
273 
274  // Warning :
275  // the image sequence is not provided with the ViSP package
276  // therefore the program will return you an error :
277  // !! vpImageIoPnm.cpp: readPGM(#210) :couldn't read file
278  // ViSP-images/mire-2/image.0001.pgm
279  // !! vpDotExample.cpp: main(#95) :Error while reading the image
280  // terminate called after throwing an instance of 'vpImageException'
281  //
282  // The sequence is available on the visp www site
283  // http://www.irisa.fr/lagadic/visp/visp.html
284  // in the download section. It is named "ViSP-images.tar.gz"
285 
286  // Set the path location of the image sequence
287  dirname = vpIoTools::createFilePath(ipath, "ViSP-images/mire-2");
288 
289  // Build the name of the image file
290 
291  s.setf(std::ios::right, std::ios::adjustfield);
292  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
293  filename = vpIoTools::createFilePath(dirname, s.str());
294  }
295  else {
296 
297  sprintf(cfilename,opt_ppath.c_str(), iter) ;
298  filename = cfilename;
299  }
300 
301  // Read the PGM image named "filename" on the disk, and put the
302  // bitmap into the image structure I. I is initialized to the
303  // correct size
304  //
305  // exception readPGM may throw various exception if, for example,
306  // the file does not exist, or if the memory cannot be allocated
307  try{
308  vpCTRACE << "Load: " << filename << std::endl;
309 
310  vpImageIo::read(I, filename) ;
311  }
312  catch(...)
313  {
314  // an exception is throwned if an exception from readPGM has been catched
315  // here this will result in the end of the program
316  // Note that another error message has been printed from readPGM
317  // to give more information about the error
318  std::cerr << std::endl
319  << "ERROR:" << std::endl;
320  std::cerr << " Cannot read " << filename << std::endl;
321  std::cerr << " Check your -i " << ipath << " option " << std::endl
322  << " or VISP_INPUT_IMAGE_PATH environment variable."
323  << std::endl;
324  exit(-1);
325  }
326 
327  // We open a window using either X11, GTK or GDI.
328 #if defined VISP_HAVE_X11
329  vpDisplayX display;
330 #elif defined VISP_HAVE_GTK
331  vpDisplayGTK display;
332 #elif defined VISP_HAVE_GDI
333  vpDisplayGDI display;
334 #elif defined VISP_HAVE_OPENCV
335  vpDisplayOpenCV display;
336 #endif
337 
338  if (opt_display) {
339  // Display size is automatically defined by the image (I) size
340  display.init(I, 100, 100,"Display...") ;
341  // Display the image
342  // The image class has a member that specify a pointer toward
343  // the display that has been initialized in the display declaration
344  // therefore is is no longuer necessary to make a reference to the
345  // display variable.
346  vpDisplay::display(I) ;
347  vpDisplay::flush(I) ;
348  }
349  // define the vpDot structure.
350 
351  // vpDot and vpDot2 correspond to two different algorithms designed to track
352  // a dot. vpDot is based on recurse connex componants (all the pixels of the
353  // dot are parsed), while vpDot2 is based on freeman chain code (only the
354  // contour of the dot is parsed)
355 
356  vpDot2 d ;
357  vpImagePoint cog;
358 
359  if (opt_display) {
360  // by using setGraphics, we request to see the all the pixel of the dot
361  // in green on the screen.
362  // It uses the overlay image plane.
363  // The default of this setting is that it is time consumming
364 
365  d.setGraphics(true) ;
366  }
367  else {
368 
369  d.setGraphics(false) ;
370  }
371  // We want to track an ellipsoid shape. If you want to track a non ellipsoid
372  // object, use d.setEllipsoidShape(0);
373  // we also request to compute the dot moment m00, m10, m01, m11, m20, m02
374  d.setComputeMoments(true);
375  d.setGrayLevelPrecision(0.90);
376 
377  // tracking is initalized if no other parameters are given to the
378  // iniTracking(..) method a right mouse click on the dot is expected
379  // dot location can also be specified explicitely in the
380  // initTracking method : d.initTracking(I,ip) where ip is the image
381  // point from which the dot is searched
382 
383  if (opt_display && opt_click_allowed) {
384  std::cout << "Click on a dot to track it."<< std::endl;
385  d.initTracking(I) ;
386  }
387  else {
388  vpImagePoint ip;
389  ip.set_u( 160 );
390  ip.set_v( 212 );
391  d.initTracking(I, ip) ;
392  }
393  if (1) {
394  std::cout << "COG: " << std::endl;
395  cog = d.getCog();
396  std::cout << " u: " << cog.get_u() << " v: " << cog.get_v()
397  << " - "
398  << d.m10 / d.m00 << " " << d.m01 / d.m00 << std::endl;
399  std::cout << "Size:" << std::endl;
400  std::cout << " w: " << d.getWidth() << " h: " << d.getHeight() << std::endl;
401  std::cout << "Area: " << d.getArea() << std::endl;
402  std::cout << "Moments:" << std::endl;
403  std::cout << " m00: " << d.m00 << std::endl;
404  std::cout << " m10: " << d.m10 << std::endl;
405  std::cout << " m01: " << d.m01 << std::endl;
406  std::cout << " m11: " << d.m11 << std::endl;
407  std::cout << " m02: " << d.m02 << std::endl;
408  std::cout << " m20: " << d.m20 << std::endl;
409  std::cout << "Centered moments:" << std::endl;
410  std::cout << " mu11: " << d.mu11 << std::endl;
411  std::cout << " mu02: " << d.mu02 << std::endl;
412  std::cout << " mu20: " << d.mu20 << std::endl;
413  std::cout << "Settings:" << std::endl;
414  std::cout << " gray level min: " << d.getGrayLevelMin() << std::endl;
415  std::cout << " gray level max: " << d.getGrayLevelMax() << std::endl;
416  std::cout << " size precision: " << d.getSizePrecision() << std::endl;
417  std::cout << " gray level precision: " << d.getGrayLevelPrecision() << std::endl;
418  }
419 
420  while (iter < opt_first + opt_nimages*opt_step) {
421  // set the new image name
422  if (opt_ppath.empty()){
423  s.str("");
424  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
425  filename = vpIoTools::createFilePath(dirname, s.str());
426  }
427  else {
428  sprintf(cfilename, opt_ppath.c_str(), iter) ;
429  filename = cfilename;
430  }
431  // read the image
432  std::cout << "read : " << filename << std::endl;
433  vpImageIo::read(I, filename);
434 
435  // track the dot and returns its coordinates in the image
436  // results are given in float since many many are usually considered
437  //
438  // an expcetion is thrown by the track method if
439  // - dot is lost
440 
441  if (opt_display) {
442  // Display the image
443  vpDisplay::display(I) ;
444  }
445 
446  std::cout << "Tracking on image: " << filename << std::endl;
447  double time = vpTime::measureTimeMs();
448  d.track(I) ;
449 
450  std::cout << "COG (" << vpTime::measureTimeMs() - time << " ms): "
451  << std::endl;
452  cog = d.getCog();
453  std::cout << " u: " << cog.get_u() << " v: " << cog.get_v()
454  << " - "
455  << d.m10 / d.m00 << " " << d.m01 / d.m00 << std::endl;
456  std::cout << "Size:" << std::endl;
457  std::cout << " w: " << d.getWidth() << " h: " << d.getHeight() << std::endl;
458  std::cout << "Area: " << d.getArea() << std::endl;
459  std::cout << "Moments:" << std::endl;
460  std::cout << " m00: " << d.m00 << std::endl;
461  std::cout << " m10: " << d.m10 << std::endl;
462  std::cout << " m01: " << d.m01 << std::endl;
463  std::cout << " m11: " << d.m11 << std::endl;
464  std::cout << " m02: " << d.m02 << std::endl;
465  std::cout << " m20: " << d.m20 << std::endl;
466  std::cout << "Centered moments:" << std::endl;
467  std::cout << " mu11: " << d.mu11 << std::endl;
468  std::cout << " mu02: " << d.mu02 << std::endl;
469  std::cout << " mu20: " << d.mu20 << std::endl;
470  std::cout << "Settings:" << std::endl;
471  std::cout << " gray level min: " << d.getGrayLevelMin() << std::endl;
472  std::cout << " gray level max: " << d.getGrayLevelMax() << std::endl;
473  std::cout << " size precision: " << d.getSizePrecision() << std::endl;
474  std::cout << " gray level precision: " << d.getGrayLevelPrecision()
475  << std::endl;
476 
477  if (opt_display) {
478  if (0) {
479  std::list<vpImagePoint> edges;
480  d.getEdges(edges);
481  std::list<vpImagePoint>::const_iterator it;
482  for(it = edges.begin(); it != edges.end(); ++it) {
484  }
485  }
486 
487  // display a green cross (size 10) in the image at the dot center
488  // of gravity location
490  // flush the X11 buffer
491 
492  vpDisplay::flush(I) ;
493  }
494  iter ++;
495  }
496 
497  if (opt_display && opt_click_allowed) {
498  std::cout << "\nA click to exit..." << std::endl;
499  // Wait for a blocking mouse click
501  }
502  return 0;
503  }
504  catch(vpException e) {
505  std::cout << "Catch an exception: " << e << std::endl;
506  return 1;
507  }
508 }
509 #else
510 #include <iostream>
511 
512 int main()
513 {
514  std::cout << "visp_me module or X11, GTK, GDI or OpenCV display functionalities are required..." << std::endl;
515 }
516 
517 #endif
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
double getWidth() const
Definition: vpDot2.cpp:644
double m02
Definition: vpDot2.h:403
double get_v() const
Definition: vpImagePoint.h:259
double mu02
Definition: vpDot2.h:422
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1091
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
double getGrayLevelPrecision() const
Definition: vpDot2.cpp:674
double get_u() const
Definition: vpImagePoint.h:248
Define the X11 console to display images.
Definition: vpDisplayX.h:148
error that can be emited by ViSP classes.
Definition: vpException.h:73
double m11
Definition: vpDot2.h:387
double getHeight() const
Definition: vpDot2.cpp:654
double getArea() const
Definition: vpDot2.cpp:664
static const vpColor green
Definition: vpColor.h:166
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:124
double m01
Definition: vpDot2.h:379
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:461
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:2233
double getSizePrecision() const
Definition: vpDot2.cpp:684
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:76
vpImagePoint getCog() const
Definition: vpDot2.h:160
void setGrayLevelPrecision(const double &grayLevelPrecision)
Definition: vpDot2.cpp:784
double mu11
Definition: vpDot2.h:412
void set_u(const double u)
Definition: vpImagePoint.h:212
double m20
Definition: vpDot2.h:394
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1265
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:206
The vpDisplayOpenCV allows to display image using the opencv library.
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void set_v(const double v)
Definition: vpImagePoint.h:223
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:141
unsigned int getGrayLevelMin() const
Definition: vpDot2.h:209
void setComputeMoments(const bool activate)
Definition: vpDot2.h:271
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:93
#define vpCTRACE
Definition: vpDebug.h:337
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:262
double m10
Definition: vpDot2.h:371
double mu20
Definition: vpDot2.h:417
virtual bool getClick(bool blocking=true)=0
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
double m00
Definition: vpDot2.h:363
static void read(vpImage< unsigned char > &I, const char *filename)
Definition: vpImageIo.cpp:274
unsigned int getGrayLevelMax() const
Definition: vpDot2.h:217
void setGraphics(const bool activate)
Definition: vpDot2.h:309
virtual void displayPoint(const vpImagePoint &ip, const vpColor &color)=0
void getEdges(std::list< vpImagePoint > &edges_list) const
Definition: vpDot2.h:174
static const vpColor blue
Definition: vpColor.h:169