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