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