ViSP  2.10.0
trackKltOpencv.cpp
1 /****************************************************************************
2  *
3  * $Id: trackKltOpencv.cpp 5108 2015-01-05 07:48:58Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 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) || defined (VISP_HAVE_OPENCV))
57 
58 #if defined (VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
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/vpDisplayOpenCV.h>
67 #include <visp/vpParseArgv.h>
68 #include <visp/vpIoTools.h>
69 
70 // List of allowed command line options
71 #define GETOPTARGS "cdf:i:n:p:s:h"
72 
73 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
74  unsigned first, unsigned nimages, unsigned step);
75 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first,
76  unsigned &nimages, unsigned &step, bool &click_allowed, bool &display);
98 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
99  unsigned first, unsigned nimages, unsigned step)
100 {
101  fprintf(stdout, "\n\
102 Example of KLT tracking using OpenCV library.\n\
103 \n\
104 SYNOPSIS\n\
105  %s [-i <test image path>] [-p <personal image path>]\n\
106  [-f <first image>] [-n <number of images>] [-s <step>]\n\
107  [-c] [-d] [-h]\n", name);
108 
109  fprintf(stdout, "\n\
110 OPTIONS: Default\n\
111  -i <input image path> %s\n\
112  Set image input path.\n\
113  From this path read images \n\
114  \"ViSP-images/mire-2/image.%%04d.pgm\". These \n\
115  images come from ViSP-images-x.y.z.tar.gz available \n\
116  on the ViSP website.\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  -c\n\
141  Disable the mouse click. Useful to automaze the \n\
142  execution of this program without humain intervention.\n\
143 \n\
144  -d \n\
145  Turn off the display.\n\
146 \n\
147  -h\n\
148  Print the help.\n",
149  ipath.c_str(), ppath.c_str(), first, nimages, step);
150 
151  if (badparam)
152  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
153 }
171 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first,
172  unsigned &nimages, unsigned &step, bool &click_allowed, bool &display)
173 {
174  const char *optarg_;
175  int c;
176  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
177 
178  switch (c) {
179  case 'c': click_allowed = false; break;
180  case 'd': display = false; break;
181  case 'i': ipath = optarg_; break;
182  case 'p': ppath = optarg_; break;
183  case 'f': first = (unsigned) atoi(optarg_); break;
184  case 'n': nimages = (unsigned) atoi(optarg_); break;
185  case 's': step = (unsigned) atoi(optarg_); break;
186  case 'h': usage(argv[0], NULL, ipath, ppath, first, nimages, step);
187  return false; break;
188 
189  default:
190  usage(argv[0], optarg_, ipath, ppath, first, nimages, step);
191  return false; break;
192  }
193  }
194 
195  if ((c == 1) || (c == -1)) {
196  // standalone param or error
197  usage(argv[0], NULL, ipath, ppath, first, nimages, step);
198  std::cerr << "ERROR: " << std::endl;
199  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
200  return false;
201  }
202 
203  return true;
204 }
205 
206 int
207 main(int argc, const char ** argv)
208 {
209  try {
210  std::string env_ipath;
211  std::string opt_ipath;
212  std::string ipath;
213  std::string opt_ppath;
214  std::string dirname;
215  std::string filename;
216  unsigned opt_first = 1;
217  unsigned opt_nimages = 500;
218  unsigned opt_step = 1;
219  bool opt_click_allowed = true;
220  bool opt_display = true;
221 
222  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
223  env_ipath = vpIoTools::getViSPImagesDataPath();
224 
225  // Set the default input path
226  if (! env_ipath.empty())
227  ipath = env_ipath;
228 
229  // Read the command line options
230  if (getOptions(argc, argv, opt_ipath, opt_ppath,opt_first, opt_nimages,
231  opt_step, opt_click_allowed, opt_display) == false) {
232  exit (-1);
233  }
234 
235  // Get the option values
236  if (!opt_ipath.empty())
237  ipath = opt_ipath;
238 
239  // Compare ipath and env_ipath. If they differ, we take into account
240  // the input path comming from the command line option
241  if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
242  if (ipath != env_ipath) {
243  std::cout << std::endl
244  << "WARNING: " << std::endl;
245  std::cout << " Since -i <visp image path=" << ipath << "> "
246  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
247  << " we skip the environment variable." << std::endl;
248  }
249  }
250 
251  // Test if an input path is set
252  if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty() ){
253  usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_nimages, opt_step);
254  std::cerr << std::endl
255  << "ERROR:" << std::endl;
256  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
257  << std::endl
258  << " environment variable to specify the location of the " << std::endl
259  << " image path where test images are located." << std::endl
260  << " Use -p <personal image path> option if you want to "<<std::endl
261  << " use personal images." << std::endl
262  << std::endl;
263 
264  exit(-1);
265  }
266 
267  // Declare an image, this is a gray level image (unsigned char)
268  // it size is not defined yet, it will be defined when the image will
269  // read on the disk
270  vpImage<unsigned char> vpI ; // This is a ViSP image used for display only
271 #if (VISP_HAVE_OPENCV_VERSION < 0x020408)
272  IplImage * cvI = NULL; // This is an OpenCV IPL image used by the tracker
273 #else
274  cv::Mat cvI;
275 #endif
276 
277  unsigned iter = opt_first;
278  std::ostringstream s;
279  char cfilename[FILENAME_MAX];
280 
281  if (opt_ppath.empty()){
282 
283 
284  // Warning :
285  // the image sequence is not provided with the ViSP package
286  // therefore the program will return you an error :
287  // !! vpImageIoPnm.cpp: readPGM(#210) :couldn't read file
288  // ViSP-images/mire-2/image.0001.pgm
289  // !! vpDotExample.cpp: main(#95) :Error while reading the image
290  // terminate called after throwing an instance of 'vpImageException'
291  //
292  // The sequence is available on the visp www site
293  // http://www.irisa.fr/lagadic/visp/visp.html
294  // in the download section. It is named "ViSP-images.tar.gz"
295 
296  // Set the path location of the image sequence
297  dirname = vpIoTools::createFilePath(ipath, "ViSP-images/mire-2");
298 
299  // Build the name of the image file
300 
301  s.setf(std::ios::right, std::ios::adjustfield);
302  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
303  filename = vpIoTools::createFilePath(dirname, s.str());
304  }
305  else {
306  sprintf(cfilename, opt_ppath.c_str(), iter) ;
307  filename = cfilename;
308  }
309 
310  // Read the PGM image named "filename" on the disk, and put the
311  // bitmap into the image structure I. I is initialized to the
312  // correct size
313  //
314  // exception readPGM may throw various exception if, for example,
315  // the file does not exist, or if the memory cannot be allocated
316  try{
317  std::cout << "Load: " << filename << std::endl;
318 
319  // Load a ViSP image used for the display
320  vpImageIo::read(vpI, filename) ;
321  vpImageConvert::convert(vpI, cvI);
322  }
323  catch(...)
324  {
325  // an exception is throwned if an exception from readPGM has been catched
326  // here this will result in the end of the program
327  // Note that another error message has been printed from readPGM
328  // to give more information about the error
329  std::cerr << std::endl
330  << "ERROR:" << std::endl;
331  std::cerr << " Cannot read " << filename << std::endl;
332  std::cerr << " Check your -i " << ipath << " option " << std::endl
333  << " or VISP_INPUT_IMAGE_PATH environment variable."
334  << std::endl;
335  exit(-1);
336  }
337 
338  // We open a window using either X11, GTK or GDI.
339 #if defined VISP_HAVE_X11
340  vpDisplayX display;
341 #elif defined VISP_HAVE_GTK
342  vpDisplayGTK display;
343 #elif defined VISP_HAVE_GDI
344  vpDisplayGDI display;
345 #elif defined VISP_HAVE_OPENCV
346  vpDisplayOpenCV display;
347 #endif
348 
349  if (opt_display) {
350  // Display size is automatically defined by the image (I) size
351  display.init(vpI, 100, 100,"Display...") ;
352  // Display the image
353  // The image class has a member that specify a pointer toward
354  // the display that has been initialized in the display declaration
355  // therefore is is no longuer necessary to make a reference to the
356  // display variable.
357  vpDisplay::display(vpI) ;
358  vpDisplay::flush(vpI) ;
359  }
360 
361  // KLT tracker
362  vpKltOpencv tracker;
363 
364  // Event manager
365  //tracker.setOnNewFeature(&newFeature);
366  //tracker.setOnFeatureLost(&lostFeature);
367  //tracker.setIsFeatureValid(&isValid);
368 
369  // Tracker parameters
370  tracker.setTrackerId(1);
371  //tracker.setOnMeasureFeature(&modifyFeature);
372  tracker.setMaxFeatures(200);
373  tracker.setWindowSize(10);
374  tracker.setQuality(0.01);
375  tracker.setMinDistance(15);
376  tracker.setHarrisFreeParameter(0.04);
377  tracker.setBlockSize(9);
378  tracker.setUseHarris(1);
379  tracker.setPyramidLevels(3);
380 
381  // Point detection using Harris. In input we have an OpenCV IPL image
382  tracker.initTracking(cvI);
383 
384  if (opt_display) {
385  // Plot the Harris points on ViSP image
386  tracker.display(vpI, vpColor::red);
387  }
388 
389  // tracking is now initialized. We can start the tracker.
390  while (iter < opt_first + opt_nimages*opt_step) {
391  // set the new image name
392  if (opt_ppath.empty()){
393  s.str("");
394  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
395  filename = vpIoTools::createFilePath(dirname, s.str());
396  }
397  else {
398  sprintf(cfilename, opt_ppath.c_str(), iter) ;
399  filename = cfilename;
400  }
401  // read the image
402  vpImageIo::read(vpI, filename) ;
403  vpImageConvert::convert(vpI, cvI);
404 
405  // track the dot and returns its coordinates in the image
406  // results are given in float since many many are usually considered
407  //
408  // an expcetion is thrown by the track method if
409  // - dot is lost
410 
411  if (opt_display) {
412  // Display the image
413  vpDisplay::display(vpI) ;
414  }
415 
416  std::cout << "Tracking on image: " << filename << std::endl;
417  double time = vpTime::measureTimeMs();
418  // Tracking of the detected points
419  tracker.track(cvI);
420  std::cout << "Tracking performed in " <<
421  vpTime::measureTimeMs() - time << " ms" << std::endl;
422 
423  if (opt_display) {
424  // Display the tracked points
425  tracker.display(vpI, vpColor::red);
426 
427  vpDisplay::flush(vpI) ;
428  }
429  iter += opt_step;
430  }
431  if (opt_display && opt_click_allowed) {
432  std::cout << "\nA click to exit..." << std::endl;
433  // Wait for a blocking mouse click
434  vpDisplay::getClick(vpI) ;
435  }
436  return 0;
437  }
438  catch(vpException e) {
439  std::cout << "Catch an exception: " << e << std::endl;
440  return 1;
441  }
442 }
443 #else
444 int
445 main()
446 {
447  vpERROR_TRACE("You do not have OpenCV functionalities...");
448 }
449 #endif
450 #else
451 int
452 main()
453 {
454  vpERROR_TRACE("You do not have X11, GTK, GDI or OpenCV display functionalities...");
455 }
456 
457 #endif
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1071
void setHarrisFreeParameter(double harris_k)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
#define vpERROR_TRACE
Definition: vpDebug.h:395
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:132
void setMaxFeatures(const int maxCount)
Define the X11 console to display images.
Definition: vpDisplayX.h:152
void setMinDistance(double minDistance)
error that can be emited by ViSP classes.
Definition: vpException.h:76
static double measureTimeMs()
Definition: vpTime.cpp:86
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:2232
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:80
static const vpColor red
Definition: vpColor.h:167
void display(const vpImage< unsigned char > &I, const vpColor &color=vpColor::red, unsigned int thickness=1)
void setQuality(double qualityLevel)
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1245
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:210
The vpDisplayOpenCV allows to display image using the opencv library.
void setTrackerId(int tid)
Does nothing. Just here for compat with previous releases that use OpenCV C api to do the tracking...
Definition: vpKltOpencv.h:152
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:145
void initTracking(const cv::Mat &I, const cv::Mat &mask=cv::Mat())
void setPyramidLevels(const int pyrMaxLevel)
void setWindowSize(const int winSize)
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV.
Definition: vpKltOpencv.h:79
void setBlockSize(const int blockSize)
virtual bool getClick(bool blocking=true)=0
void setUseHarris(const int useHarrisDetector)
static void read(vpImage< unsigned char > &I, const char *filename)
Definition: vpImageIo.cpp:278
void track(const cv::Mat &I)