Visual Servoing Platform  version 3.0.0
trackDot2WithAutoDetection.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  * Test auto detection of dots.
32  *
33  * Authors:
34  * Fabien Spindler
35  *
36  *****************************************************************************/
49 #include <visp3/core/vpDebug.h>
50 #include <visp3/core/vpConfig.h>
51 
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <sstream>
55 #include <iomanip>
56 
57 #if defined(VISP_HAVE_MODULE_BLOB) && (defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
58 
59 #include <visp3/core/vpImage.h>
60 #include <visp3/io/vpImageIo.h>
61 #include <visp3/core/vpImagePoint.h>
62 #include <visp3/gui/vpDisplayX.h>
63 #include <visp3/gui/vpDisplayGTK.h>
64 #include <visp3/gui/vpDisplayGDI.h>
65 #include <visp3/gui/vpDisplayOpenCV.h>
66 #include <visp3/blob/vpDot2.h>
67 #include <visp3/io/vpParseArgv.h>
68 #include <visp3/core/vpIoTools.h>
69 
70 // List of allowed command line options
71 #define GETOPTARGS "cdi:p:f:n:s:S:G:E:h"
72 
73 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
74  unsigned first, unsigned nimages, unsigned step, double sizePrecision,
75  double grayLevelPrecision, double ellipsoidShapePrecision );
76 bool getOptions(int argc, const char **argv, std::string &ipath,
77  std::string &ppath,unsigned &first, unsigned &nimages,
78  unsigned &step, double &sizePrecision, double &grayLevelPrecision,
79  double &ellipsoidShapePrecision, bool &click_allowed, bool &display);
80 
98 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
99  unsigned first, unsigned nimages, unsigned step, double sizePrecision,
100  double grayLevelPrecision, double ellipsoidShapePrecision)
101 {
102  fprintf(stdout, "\n\
103 Test auto detection of dots using vpDot2.\n\
104  \n\
105 SYNOPSIS\n\
106  %s [-i <input image path>] [-p <personal image path>]\n\
107  [-f <first image>] [-n <number of images>] [-s <step>] \n\
108  [-S <size precision>] [-G <gray level precision>]\n\
109  [-E <ellipsoid shape precision>] [-c] [-d] [-h]\n", name);
110 
111  fprintf(stdout, "\n\
112 OPTIONS: Default\n\
113  -i <input image path> %s\n\
114  Set image input path.\n\
115  From this path read images \n\
116  \"ViSP-images/mire-2/image.%%04d.pgm\"\n\
117  Setting the VISP_INPUT_IMAGE_PATH environment\n\
118  variable produces the same behaviour than using\n\
119  this option.\n\
120  \n\
121  -p <personal image path> %s\n\
122  Specify a personal sequence containing images \n\
123  to process.\n\
124  By image sequence, we mean one file per image.\n\
125  The following image file formats PNM (PGM P5, PPM P6)\n\
126  are supported. The format is selected by analysing \n\
127  the filename extension.\n\
128  Example : \"/Temp/ViSP-images/cube/image.%%04d.pgm\"\n\
129  %%04d is for the image numbering.\n\
130  \n\
131  -f <first image> %u\n\
132  First image number of the sequence.\n\
133  \n\
134  -n <number of images> %u\n\
135  Number of images to load from the sequence.\n\
136  \n\
137  -s <step> %u\n\
138  Step between two images.\n\
139  \n\
140  -S <size precision> %f\n\
141  Precision of the size of the dot. \n\
142  It is a double precision float witch value is in ]0,1].\n\
143  1 means full precision, the sizes (width, heigth, surface) \n\
144  of the dots must the same, whereas values close to 0 \n\
145  show a very bad precision.\n\
146 \n\
147  -G <gray level precision> %f\n\
148  Precision of the gray level of the dot. \n\
149  It is a double precision float witch value is in ]0,1].\n\
150  1 means full precision, the gray level must the same in \n\
151  the wall dot, whereas values close to 0 \n\
152  show a very bad precision.\n\
153 \n\
154  -E <ellipsoid shape precision> %f\n\
155  Precision of the ellipsoid shape of the dot. \n\
156  It is a double precision float witch value is in [0,1].\n\
157  1 means full precision, the shape should be a perfect ellipsoid,\n\
158  whereas values close to 0 show a very bad precision.\n\
159  0 means the shape of dots is not tested \n\
160 \n",
161 ipath.c_str(),ppath.c_str(), first, nimages, step, sizePrecision,
162 grayLevelPrecision, ellipsoidShapePrecision );
163 
164  fprintf(stdout, "\
165  -c\n\
166  Disable the mouse click. Useful to automaze the \n\
167  execution of this program without humain intervention.\n\
168  \n\
169  -d \n\
170  Turn off the display.\n\
171  \n\
172  -h\n\
173  Print the help.\n");
174 
175  if (badparam)
176  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
177 }
198 bool getOptions(int argc, const char **argv, std::string &ipath,
199  std::string &ppath,unsigned &first, unsigned &nimages,
200  unsigned &step, double &sizePrecision, double &grayLevelPrecision,
201  double &ellipsoidShapePrecision, bool &click_allowed, bool &display)
202 {
203  const char *optarg_;
204  int c;
205  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
206 
207  switch (c) {
208  case 'c': click_allowed = false; break;
209  case 'd': display = false; break;
210  case 'i': ipath = optarg_; break;
211  case 'p': ppath = optarg_; break;
212  case 'f': first = (unsigned) atoi(optarg_); break;
213  case 'n': nimages = (unsigned) atoi(optarg_); break;
214  case 's': step = (unsigned) atoi(optarg_); break;
215  case 'S': sizePrecision = atof(optarg_);break;
216  case 'G': grayLevelPrecision = atof(optarg_);break;
217  case 'E': ellipsoidShapePrecision = atof(optarg_);break;
218  case 'h': usage(argv[0], NULL, ipath, ppath, first, nimages, step,
219  sizePrecision,grayLevelPrecision,ellipsoidShapePrecision);
220  return false; break;
221 
222  default:
223  usage(argv[0], optarg_, ipath, ppath, first, nimages, step,
224  sizePrecision,grayLevelPrecision,ellipsoidShapePrecision);
225  return false; break;
226  }
227  }
228 
229  if ((c == 1) || (c == -1)) {
230  // standalone param or error
231  usage(argv[0], NULL, ipath, ppath, first, nimages, step,
232  sizePrecision,grayLevelPrecision,ellipsoidShapePrecision);
233  std::cerr << "ERROR: " << std::endl;
234  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
235  return false;
236  }
237 
238  return true;
239 }
240 
241 
242 int
243 main(int argc, const char ** argv)
244 {
245  try {
246  std::string env_ipath;
247  std::string opt_ipath;
248  std::string ipath;
249  std::string opt_ppath;
250  std::string dirname;
251  std::string filename;
252  unsigned opt_first = 1;
253  unsigned opt_nimages = 10;
254  unsigned opt_step = 1;
255  double opt_sizePrecision = 0.65;
256  double opt_grayLevelPrecision = 0.85;
257  double opt_ellipsoidShapePrecision = 0.8;
258  bool opt_click_allowed = true;
259  bool opt_display = true;
260 
261  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
262  env_ipath = vpIoTools::getViSPImagesDataPath();
263 
264  // Set the default input path
265  if (! env_ipath.empty())
266  ipath = env_ipath;
267 
268  // Read the command line options
269  if (getOptions(argc, argv, opt_ipath, opt_ppath,opt_first, opt_nimages,
270  opt_step,opt_sizePrecision,opt_grayLevelPrecision,
271  opt_ellipsoidShapePrecision, opt_click_allowed, opt_display) == false) {
272  exit (-1);
273  }
274 
275  // Get the option values
276  if (!opt_ipath.empty())
277  ipath = opt_ipath;
278 
279  // Compare ipath and env_ipath. If they differ, we take into account
280  // the input path comming from the command line option
281  if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
282  if (ipath != env_ipath) {
283  std::cout << std::endl
284  << "WARNING: " << std::endl;
285  std::cout << " Since -i <visp image path=" << ipath << "> "
286  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
287  << " we skip the environment variable." << std::endl;
288  }
289  }
290 
291  // Test if an input path is set
292  if (opt_ipath.empty() && env_ipath.empty()){
293  usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_nimages,
294  opt_step,opt_sizePrecision,opt_grayLevelPrecision, opt_ellipsoidShapePrecision);
295  std::cerr << std::endl
296  << "ERROR:" << std::endl;
297  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
298  << std::endl
299  << " environment variable to specify the location of the " << std::endl
300  << " image path where test images are located." << std::endl << std::endl
301  << " Use -p <personal image path> option if you want to "<<std::endl
302  << " use personal images." << std::endl;
303  exit(-1);
304  }
305 
306 
307  // Declare an image, this is a gray level image (unsigned char)
308  // it size is not defined yet, it will be defined when the image will
309  // read on the disk
311  std::ostringstream s;
312  char cfilename[FILENAME_MAX];
313  unsigned iter = opt_first; // Image number
314 
315  if (opt_ppath.empty()){
316 
317 
318  // Warning :
319  // the image sequence is not provided with the ViSP package
320  // therefore the program will return you an error :
321  // !! vpImageIoPnm.cpp: readPGM(#210) :couldn't read file
322  // ViSP-images/cube/image.0001.pgm
323  // !! vpDotExample.cpp: main(#95) :Error while reading the image
324  // terminate called after throwing an instance of 'vpImageException'
325  //
326  // The sequence is available on the visp www site
327  // http://www.irisa.fr/lagadic/visp/visp.html
328  // in the download section. It is named "ViSP-images.tar.gz"
329 
330  // Set the path location of the image sequence
331  dirname = vpIoTools::createFilePath(ipath, "ViSP-images/mire-2");
332 
333  // Build the name of the image file
334 
335  s.setf(std::ios::right, std::ios::adjustfield);
336  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
337  filename = vpIoTools::createFilePath(dirname, s.str());
338  }
339  else {
340 
341  sprintf(cfilename,opt_ppath.c_str(), iter) ;
342  filename = cfilename;
343  }
344  // Read the PGM image named "filename" on the disk, and put the
345  // bitmap into the image structure I. I is initialized to the
346  // correct size
347  //
348  // exception readPGM may throw various exception if, for example,
349  // the file does not exist, or if the memory cannot be allocated
350  try{
351  vpCTRACE << "Load: " << filename << std::endl;
352 
353  vpImageIo::read(I, filename) ;
354  }
355  catch(...)
356  {
357  // an exception is throwned if an exception from readPGM has been catched
358  // here this will result in the end of the program
359  // Note that another error message has been printed from readPGM
360  // to give more information about the error
361  std::cerr << std::endl
362  << "ERROR:" << std::endl;
363  std::cerr << " Cannot read " << filename << std::endl;
364  std::cerr << " Check your -i " << ipath << " option " << std::endl
365  << " or your -p " << opt_ppath << " option " <<std::endl
366  << " or VISP_INPUT_IMAGE_PATH environment variable."
367  << std::endl;
368  exit(-1);
369  }
370 
371 
372  // We open a window using either GTK, X11 or GDI.
373 #if defined VISP_HAVE_GTK
374  vpDisplayGTK display;
375 #elif defined VISP_HAVE_X11
376  vpDisplayX display;
377 #elif defined VISP_HAVE_GDI
378  vpDisplayGDI display;
379 #elif defined VISP_HAVE_OPENCV
380  vpDisplayOpenCV display;
381 #endif
382 
383  if (opt_display) {
384  // Display size is automatically defined by the image (I) size
385  display.init(I, 100, 100,"Display...") ;
386  // Display the image
387  // The image class has a member that specify a pointer toward
388  // the display that has been initialized in the display declaration
389  // therefore is is no longuer necessary to make a reference to the
390  // display variable.
391  vpDisplay::display(I) ;
392  vpDisplay::flush(I) ;
393  }
394 
395  // Dot declaration
396  vpDot2 d ;
397 
398  d.setGraphics(true);
399  if (opt_click_allowed & opt_display) {
400  d.setGrayLevelPrecision(opt_grayLevelPrecision);
401 
402  std::cout << "Please click on a dot to initialize detection"
403  << std::endl;
404 
405  d.initTracking(I) ;
406  if (opt_display) {
407  vpImagePoint cog;
408  cog = d.getCog();
410  vpDisplay::flush(I) ;
411  }
412  d.setSizePrecision(opt_sizePrecision);
413  d.setEllipsoidShapePrecision(opt_ellipsoidShapePrecision);
414  printf("Dot characteristics: \n");
415  printf(" width : %lf\n", d.getWidth());
416  printf(" height: %lf\n", d.getHeight());
417  printf(" area: %lf\n", d.getArea());
418  printf(" gray level min: %d\n", d.getGrayLevelMin());
419  printf(" gray level max: %d\n", d.getGrayLevelMax());
420  printf(" grayLevelPrecision: %lf\n", d.getGrayLevelPrecision());
421  printf(" sizePrecision: %lf\n", d.getSizePrecision());
422  printf(" ellipsoidShapePrecision: %lf\n", d.getEllipsoidShapePrecision());
423  }
424  else{
425  // Set dot characteristics for the auto detection
426  d.setGraphics(true);
427  d.setWidth(15.0);
428  d.setHeight(12.0);
429  d.setArea(124);
430  d.setGrayLevelMin(164);
431  d.setGrayLevelMax(255);
432  d.setGrayLevelPrecision(opt_grayLevelPrecision);
433  d.setSizePrecision(opt_sizePrecision);
434  d.setEllipsoidShapePrecision(opt_ellipsoidShapePrecision);
435  }
436 
437  while (iter < opt_first + opt_nimages*opt_step)
438  {
439  // set the new image name
440 
441  if (opt_ppath.empty()){
442 
443  s.str("");
444  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
445  filename = vpIoTools::createFilePath(dirname, s.str());
446  }
447  else {
448  sprintf(cfilename, opt_ppath.c_str(), iter) ;
449  filename = cfilename;
450  }
451  // read the image
452  vpImageIo::read(I, filename);
453 
454  if (opt_display) {
455  // Display the image
456  vpDisplay::display(I) ;
457  }
458 
459  std::cout << "Search dots in image" << filename << std::endl;
460  std::list<vpDot2> list_d;
461  d.searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), list_d) ;
462 
463  if( list_d.empty() ) {
464  std::cout << "Dot auto detection did not work." << std::endl;
465  return(-1) ;
466  }
467  else {
468  std::cout << std::endl << list_d.size() << " dots are detected" << std::endl;
469 
470  if (opt_display) {
471  int i=0;
472  // Parse all founded dots for display
473  for (std::list<vpDot2>::const_iterator it = list_d.begin(); it != list_d.end(); ++ it)
474  {
475  vpImagePoint cog = (*it).getCog();
476 
477  std::cout << "Dot " << i++ << " : " << cog.get_u()
478  << " " << cog.get_v() << std::endl;
479 
480  vpDisplay::displayCross(I, cog, 16, vpColor::blue, 3) ;
481  }
482  vpDisplay::flush(I);
483  }
484  }
485 
486  // If click is allowed, wait for a mouse click to launch the next iteration
487  if (opt_display && opt_click_allowed) {
488  std::cout << "\nA click to continue..." << std::endl;
489  // Wait for a blocking mouse click
491  }
492 
493  iter += opt_step ;
494  }
495  if (opt_display && opt_click_allowed) {
496  std::cout << "\nA click to exit..." << std::endl;
497  // Wait for a blocking mouse click
499  }
500 
501  return 0;
502  }
503  catch(vpException e) {
504  std::cout << "Catch an exception: " << e << std::endl;
505  return 1;
506  }
507 }
508 #else
509 #include <iostream>
510 
511 int main()
512 {
513  std::cout << "visp_me module or X11, GTK, GDI or OpenCV display functionalities are required..." << std::endl;
514 }
515 
516 #endif
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
double getWidth() const
Definition: vpDot2.cpp:644
void setGrayLevelMax(const unsigned int &max)
Definition: vpDot2.h:344
double get_v() const
Definition: vpImagePoint.h:259
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)
Definition: vpDot2.cpp:1041
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1091
unsigned int getWidth() const
Definition: vpImage.h:161
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 getHeight() const
Definition: vpDot2.cpp:654
double getArea() const
Definition: vpDot2.cpp:664
double getEllipsoidShapePrecision() const
Definition: vpDot2.cpp:696
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
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
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
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 setArea(const double &area)
Definition: vpDot2.cpp:763
void setEllipsoidShapePrecision(const double &ellipsoidShapePrecision)
Definition: vpDot2.cpp:859
void setGrayLevelMin(const unsigned int &min)
Definition: vpDot2.h:328
void setWidth(const double &width)
Definition: vpDot2.cpp:734
void setSizePrecision(const double &sizePrecision)
Definition: vpDot2.cpp:814
#define vpCTRACE
Definition: vpDebug.h:337
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:262
void setHeight(const double &height)
Definition: vpDot2.cpp:749
unsigned int getHeight() const
Definition: vpImage.h:152
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
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
static const vpColor blue
Definition: vpColor.h:169