ViSP  2.8.0
trackKltOpencv.cpp
1 /****************************************************************************
2  *
3  * $Id: trackKltOpencv.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 <stdio.h>
52 #include <sstream>
53 #include <iomanip>
54 #include <vector>
55 
56 #if (defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI))
57 
58 #if (defined (VISP_HAVE_OPENCV))
59 
60 #include <visp/vpKltOpencv.h>
61 #include <visp/vpImage.h>
62 #include <visp/vpImageIo.h>
63 #include <visp/vpDisplayX.h>
64 #include <visp/vpDisplayGTK.h>
65 #include <visp/vpDisplayGDI.h>
66 #include <visp/vpParseArgv.h>
67 #include <visp/vpIoTools.h>
68 
69 // List of allowed command line options
70 #define GETOPTARGS "cdf:i:n:p:s:h"
71 
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 Example of KLT tracking using OpenCV library.\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 : \"/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,
167  unsigned &first, unsigned &nimages, unsigned &step,
168  bool &click_allowed, bool &display)
169 {
170  const char *optarg;
171  int c;
172  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg)) > 1) {
173 
174  switch (c) {
175  case 'c': click_allowed = false; break;
176  case 'd': display = false; break;
177  case 'i': ipath = optarg; break;
178  case 'p': ppath = optarg; break;
179  case 'f': first = (unsigned) atoi(optarg); break;
180  case 'n': nimages = (unsigned) atoi(optarg); break;
181  case 's': step = (unsigned) atoi(optarg); break;
182  case 'h': usage(argv[0], NULL, ipath, ppath, first, nimages, step);
183  return false; break;
184 
185  default:
186  usage(argv[0], optarg, ipath, ppath, first, nimages, step);
187  return false; break;
188  }
189  }
190 
191  if ((c == 1) || (c == -1)) {
192  // standalone param or error
193  usage(argv[0], NULL, ipath, ppath, first, nimages, step);
194  std::cerr << "ERROR: " << std::endl;
195  std::cerr << " Bad argument " << optarg << std::endl << std::endl;
196  return false;
197  }
198 
199  return true;
200 }
201 
202 int
203 main(int argc, const char ** argv)
204 {
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_IMAGE_PATH environment variable value
218  char *ptenv = getenv("VISP_INPUT_IMAGE_PATH");
219  if (ptenv != NULL)
220  env_ipath = ptenv;
221 
222  // Set the default input path
223  if (! env_ipath.empty())
224  ipath = env_ipath;
225 
226 
227  // Read the command line options
228  if (getOptions(argc, argv, opt_ipath, opt_ppath,opt_first, opt_nimages,
229  opt_step, opt_click_allowed, opt_display) == false) {
230  exit (-1);
231  }
232 
233  // Get the option values
234  if (!opt_ipath.empty())
235  ipath = opt_ipath;
236 
237  // Compare ipath and env_ipath. If they differ, we take into account
238  // the input path comming from the command line option
239  if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
240  if (ipath != env_ipath) {
241  std::cout << std::endl
242  << "WARNING: " << std::endl;
243  std::cout << " Since -i <visp image path=" << ipath << "> "
244  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
245  << " we skip the environment variable." << std::endl;
246  }
247  }
248 
249  // Test if an input path is set
250  if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty() ){
251  usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_nimages, opt_step);
252  std::cerr << std::endl
253  << "ERROR:" << std::endl;
254  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
255  << std::endl
256  << " environment variable to specify the location of the " << std::endl
257  << " image path where test images are located." << std::endl
258  << " Use -p <personal image path> option if you want to "<<std::endl
259  << " use personal images." << std::endl
260  << std::endl;
261 
262  exit(-1);
263  }
264 
265  // Declare an image, this is a gray level image (unsigned char)
266  // it size is not defined yet, it will be defined when the image will
267  // read on the disk
268  vpImage<unsigned char> vpI ; // This is a ViSP image used for display only
269  IplImage * cvI; // This is an OpenCV IPL image used by the tracker
270 
271  unsigned iter = opt_first;
272  std::ostringstream s;
273  char cfilename[FILENAME_MAX];
274 
275  if (opt_ppath.empty()){
276 
277 
278  // Warning :
279  // the image sequence is not provided with the ViSP package
280  // therefore the program will return you an error :
281  // !! vpImageIoPnm.cpp: readPGM(#210) :couldn't read file
282  // ViSP-images/mire-2/image.0001.pgm
283  // !! vpDotExample.cpp: main(#95) :Error while reading the image
284  // terminate called after throwing an instance of 'vpImageException'
285  //
286  // The sequence is available on the visp www site
287  // http://www.irisa.fr/lagadic/visp/visp.html
288  // in the download section. It is named "ViSP-images.tar.gz"
289 
290  // Set the path location of the image sequence
291  dirname = ipath + vpIoTools::path("/ViSP-images/mire-2/");
292 
293  // Build the name of the image file
294 
295  s.setf(std::ios::right, std::ios::adjustfield);
296  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
297  filename = dirname + s.str();
298  }
299  else {
300 
301  sprintf(cfilename,opt_ppath.c_str(), iter) ;
302  filename = cfilename;
303  }
304 
305  // Read the PGM image named "filename" on the disk, and put the
306  // bitmap into the image structure I. I is initialized to the
307  // correct size
308  //
309  // exception readPGM may throw various exception if, for example,
310  // the file does not exist, or if the memory cannot be allocated
311  try{
312  vpCTRACE << "Load: " << filename << std::endl;
313 
314  // Load a ViSP image used for the display
315  vpImageIo::read(vpI, filename) ;
316  // Load an OpenCV IPL image used by the tracker
317  if((cvI = cvLoadImage(filename.c_str(), CV_LOAD_IMAGE_GRAYSCALE))== NULL) {
318  printf("Cannot read image: %s\n", filename.c_str());
319  return (0);
320  }
321  }
322  catch(...)
323  {
324  // an exception is throwned if an exception from readPGM has been catched
325  // here this will result in the end of the program
326  // Note that another error message has been printed from readPGM
327  // to give more information about the error
328  std::cerr << std::endl
329  << "ERROR:" << std::endl;
330  std::cerr << " Cannot read " << filename << std::endl;
331  std::cerr << " Check your -i " << ipath << " option " << std::endl
332  << " or VISP_INPUT_IMAGE_PATH environment variable."
333  << std::endl;
334  exit(-1);
335  }
336 
337  // We open a window using either X11, GTK or GDI.
338 #if defined VISP_HAVE_X11
339  vpDisplayX display;
340 #elif defined VISP_HAVE_GTK
341  vpDisplayGTK display;
342 #elif defined VISP_HAVE_GDI
343  vpDisplayGDI display;
344 #endif
345 
346  if (opt_display) {
347  try{
348  // Display size is automatically defined by the image (I) size
349  display.init(vpI, 100, 100,"Display...") ;
350  // Display the image
351  // The image class has a member that specify a pointer toward
352  // the display that has been initialized in the display declaration
353  // therefore is is no longuer necessary to make a reference to the
354  // display variable.
355  vpDisplay::display(vpI) ;
356  vpDisplay::flush(vpI) ;
357  }
358  catch(...)
359  {
360  // an exception is throwned if an exception from readPGM has been catched
361  // here this will result in the end of the program
362  // Note that another error message has been printed from readPGM
363  // to give more information about the error
364 
365  vpERROR_TRACE("Error while displaying the image") ;
366  exit(-1);
367  }
368  }
369 
370  // KLT tracker
371  vpKltOpencv tracker;
372 
373  // Event manager
374  //tracker.setOnNewFeature(&newFeature);
375  //tracker.setOnFeatureLost(&lostFeature);
376  //tracker.setIsFeatureValid(&isValid);
377 
378  // Tracker parameters
379  tracker.setTrackerId(1);
380  //tracker.setOnMeasureFeature(&modifyFeature);
381  tracker.setMaxFeatures(200);
382  tracker.setWindowSize(10);
383  tracker.setQuality(0.01);
384  tracker.setMinDistance(15);
385  tracker.setHarrisFreeParameter(0.04);
386  tracker.setBlockSize(9);
387  tracker.setUseHarris(1);
388  tracker.setPyramidLevels(3);
389 
390  // Point detection using Harris. In input we have an OpenCV IPL image
391  tracker.initTracking(cvI);
392 
393  if (opt_display) {
394  // Plot the Harris points on ViSP image
395  tracker.display(vpI, vpColor::red);
396  }
397 
398  // tracking is now initialized. We can start the tracker.
399 
400  try {
401  while (iter < opt_first + opt_nimages*opt_step) {
402  // set the new image name
403  if (opt_ppath.empty()){
404  s.str("");
405  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
406  filename = dirname + s.str();
407  }
408  else {
409  sprintf(cfilename, opt_ppath.c_str(), iter) ;
410  filename = cfilename;
411  }
412  // read the image
413  std::cout << "read : " << filename << std::endl;
414  // Load a ViSP image used for the display
415  vpImageIo::read(vpI, filename) ;
416  // Load an OpenCV IPL image used by the tracker
417  if((cvI = cvLoadImage(filename.c_str(), CV_LOAD_IMAGE_GRAYSCALE))
418  == NULL) {
419  printf("Cannot read image: %s\n", filename.c_str());
420  return (0);
421  }
422 
423  // track the dot and returns its coordinates in the image
424  // results are given in float since many many are usually considered
425  //
426  // an expcetion is thrown by the track method if
427  // - dot is lost
428 
429  if (opt_display) {
430  // Display the image
431  vpDisplay::display(vpI) ;
432  }
433 
434  std::cout << "Tracking on image: " << filename << std::endl;
435  double time = vpTime::measureTimeMs();
436  // Tracking of the detected points
437  tracker.track(cvI);
438  std::cout << "Tracking performed in " <<
439  vpTime::measureTimeMs() - time << " ms): " << std::endl;
440 
441  if (opt_display) {
442  // Display the tracked points
443  tracker.display(vpI, vpColor::red);
444 
445  vpDisplay::flush(vpI) ;
446  }
447  iter += opt_step;
448  }
449  }
450  catch (...) {
451  std::cerr << "Error during the tracking..." << std::endl;
452  std::cerr << "The progam was stopped." << std::endl;
453  exit(-1);
454  }
455  if (opt_display && opt_click_allowed) {
456  std::cout << "\nA click to exit..." << std::endl;
457  // Wait for a blocking mouse click
458  vpDisplay::getClick(vpI) ;
459  }
460 }
461 #else
462 int
463 main()
464 {
465  vpERROR_TRACE("You do not have OpenCV functionalities...");
466 }
467 #endif
468 #else
469 int
470 main()
471 {
472  vpERROR_TRACE("You do not have X11, GTK or GDI display functionalities...");
473 }
474 
475 #endif
void setQuality(double input)
Definition: vpKltOpencv.h:263
void track(const IplImage *I)
#define vpERROR_TRACE
Definition: vpDebug.h:379
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:133
void setUseHarris(const int input)
Definition: vpKltOpencv.h:272
Define the X11 console to display images.
Definition: vpDisplayX.h:152
void display(const vpImage< unsigned char > &I, vpColor color=vpColor::red, unsigned int thickness=1)
static std::string path(const char *pathname)
Definition: vpIoTools.cpp:715
void setPyramidLevels(const int input)
Definition: vpKltOpencv.h:262
void setBlockSize(const int input)
Definition: vpKltOpencv.h:218
static double measureTimeMs()
Definition: vpTime.cpp:86
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1991
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:79
static const vpColor red
Definition: vpColor.h:167
#define vpCTRACE
Definition: vpDebug.h:327
void setWindowSize(const int input)
Definition: vpKltOpencv.h:273
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:203
void setTrackerId(int tid)
Definition: vpKltOpencv.h:264
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:145
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
void initTracking(const IplImage *I, const IplImage *mask=NULL)
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV.
Definition: vpKltOpencv.h:103
virtual bool getClick(bool blocking=true)=0
void setMaxFeatures(const int input)
static void read(vpImage< unsigned char > &I, const char *filename)
Definition: vpImageIo.cpp:277
void setMinDistance(double input)
Definition: vpKltOpencv.h:242
void setHarrisFreeParameter(double input)
Definition: vpKltOpencv.h:226