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