Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
mbtKltMultiTracking.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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  * Example of MBT KLT Tracking.
32  *
33  * Authors:
34  * Aurelien Yol
35  * Souriya Trinh
36  *
37  *****************************************************************************/
38 
45 #include <iostream>
46 #include <visp3/core/vpConfig.h>
47 
48 #if defined(VISP_HAVE_MODULE_MBT) && defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(VISP_HAVE_DISPLAY) && (VISP_HAVE_OPENCV_VERSION >= 0x020100)
49 
50 #include <visp3/core/vpDebug.h>
51 #include <visp3/gui/vpDisplayD3D.h>
52 #include <visp3/gui/vpDisplayGTK.h>
53 #include <visp3/gui/vpDisplayGDI.h>
54 #include <visp3/gui/vpDisplayOpenCV.h>
55 #include <visp3/gui/vpDisplayX.h>
56 #include <visp3/core/vpHomogeneousMatrix.h>
57 #include <visp3/io/vpImageIo.h>
58 #include <visp3/core/vpIoTools.h>
59 #include <visp3/core/vpMath.h>
60 #include <visp3/io/vpVideoReader.h>
61 #include <visp3/io/vpParseArgv.h>
62 #include <visp3/mbt/vpMbKltMultiTracker.h>
63 
64 #define GETOPTARGS "x:m:i:n:dchtfolwv"
65 
66 
67 void usage(const char *name, const char *badparam)
68 {
69  fprintf(stdout, "\n\
70 Example of tracking based on the 3D model.\n\
71 \n\
72 SYNOPSIS\n\
73  %s [-i <test image path>] [-x <config file>]\n\
74  [-m <model name>] [-n <initialisation file base name>]\n\
75  [-t] [-c] [-d] [-h] [-f] [-o] [-w] [-l] [-v]",
76  name );
77 
78  fprintf(stdout, "\n\
79 OPTIONS: \n\
80  -i <input image path> \n\
81  Set image input path.\n\
82  From this path read images \n\
83  \"ViSP-images/mbt/cube/image%%04d.ppm\". These \n\
84  images come from ViSP-images-x.y.z.tar.gz available \n\
85  on the ViSP website.\n\
86  Setting the VISP_INPUT_IMAGE_PATH environment\n\
87  variable produces the same behavior than using\n\
88  this option.\n\
89 \n\
90  -x <config file> \n\
91  Set the config file (the xml file) to use.\n\
92  The config file is used to specify the parameters of the tracker.\n\
93 \n\
94  -m <model name> \n\
95  Specify the name of the file of the model\n\
96  The model can either be a vrml model (.wrl) or a .cao file.\n\
97 \n\
98  -f \n\
99  Do not use the vrml model, use the .cao one. These two models are \n\
100  equivalent and comes from ViSP-images-x.y.z.tar.gz available on the ViSP\n\
101  website. However, the .cao model allows to use the 3d model based tracker \n\
102  without Coin.\n\
103 \n\
104  -n <initialisation file base name> \n\
105  Base name of the initialisation file. The file will be 'base_name'.init .\n\
106  This base name is also used for the optional picture specifying where to \n\
107  click (a .ppm picture).\
108 \n\
109  -t \n\
110  Turn off the display of the the klt points. \n\
111 \n\
112  -d \n\
113  Turn off the display.\n\
114 \n\
115  -c\n\
116  Disable the mouse click. Useful to automate the \n\
117  execution of this program without human intervention.\n\
118 \n\
119  -o\n\
120  Use Ogre3D for visibility tests\n\
121 \n\
122  -w\n\
123  When Ogre3D is enable [-o] show Ogre3D configuration dialog that allows to set the renderer.\n\
124 \n\
125  -l\n\
126  Use the scanline for visibility tests.\n\
127 \n\
128  -v\n\
129  Compute covariance matrix.\n\
130 \n\
131  -h \n\
132  Print the help.\n\n");
133 
134  if (badparam)
135  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
136 }
137 
138 
139 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &configFile, std::string &modelFile,
140  std::string &initFile, bool &displayKltPoints, bool &click_allowed, bool &display,
141  bool& cao3DModel, bool &useOgre, bool &showOgreConfigDialog, bool &useScanline, bool &computeCovariance)
142 {
143  const char *optarg_;
144  int c;
145  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
146 
147  switch (c) {
148  case 'i': ipath = optarg_; break;
149  case 'x': configFile = optarg_; break;
150  case 'm': modelFile = optarg_; break;
151  case 'n': initFile = optarg_; break;
152  case 't': displayKltPoints = false; break;
153  case 'f': cao3DModel = true; break;
154  case 'c': click_allowed = false; break;
155  case 'd': display = false; break;
156  case 'o': useOgre = true; break;
157  case 'l': useScanline = true; break;
158  case 'w': showOgreConfigDialog = true; break;
159  case 'v': computeCovariance = true; break;
160  case 'h': usage(argv[0], NULL); return false; break;
161 
162  default:
163  usage(argv[0], optarg_);
164  return false; break;
165  }
166  }
167 
168  if ((c == 1) || (c == -1)) {
169  // standalone param or error
170  usage(argv[0], NULL);
171  std::cerr << "ERROR: " << std::endl;
172  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
173  return false;
174  }
175 
176  return true;
177 }
178 
179 int
180 main(int argc, const char ** argv)
181 {
182  try {
183  std::string env_ipath;
184  std::string opt_ipath;
185  std::string ipath;
186  std::string opt_configFile;
187  std::string configFile;
188  std::string opt_modelFile;
189  std::string modelFile;
190  std::string opt_initFile;
191  std::string initFile;
192  bool displayKltPoints = true;
193  bool opt_click_allowed = true;
194  bool opt_display = true;
195  bool cao3DModel = false;
196  bool useOgre = false;
197  bool showOgreConfigDialog = false;
198  bool useScanline = false;
199  bool computeCovariance = false;
200  bool quit = false;
201 
202  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
203  env_ipath = vpIoTools::getViSPImagesDataPath();
204 
205  // Set the default input path
206  if (! env_ipath.empty())
207  ipath = env_ipath;
208 
209  // Read the command line options
210  if (!getOptions(argc, argv, opt_ipath, opt_configFile, opt_modelFile, opt_initFile, displayKltPoints,
211  opt_click_allowed, opt_display, cao3DModel, useOgre, showOgreConfigDialog, useScanline,
212  computeCovariance)) {
213  return (-1);
214  }
215 
216  // Test if an input path is set
217  if (opt_ipath.empty() && env_ipath.empty() ){
218  usage(argv[0], NULL);
219  std::cerr << std::endl
220  << "ERROR:" << std::endl;
221  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
222  << std::endl
223  << " environment variable to specify the location of the " << std::endl
224  << " image path where test images are located." << std::endl
225  << std::endl;
226 
227  return (-1);
228  }
229 
230  // Get the option values
231  if (!opt_ipath.empty())
232  ipath = vpIoTools::createFilePath(opt_ipath, "ViSP-images/mbt/cube/image%04d.pgm");
233  else
234  ipath = vpIoTools::createFilePath(env_ipath, "ViSP-images/mbt/cube/image%04d.pgm");
235 
236  if (!opt_configFile.empty())
237  configFile = opt_configFile;
238  else if (!opt_ipath.empty())
239  configFile = vpIoTools::createFilePath(opt_ipath, "ViSP-images/mbt/cube.xml");
240  else
241  configFile = vpIoTools::createFilePath(env_ipath, "ViSP-images/mbt/cube.xml");
242 
243  if (!opt_modelFile.empty()){
244  modelFile = opt_modelFile;
245  }else{
246  std::string modelFileCao = "ViSP-images/mbt/cube.cao";
247  std::string modelFileWrl = "ViSP-images/mbt/cube.wrl";
248 
249  if(!opt_ipath.empty()){
250  if(cao3DModel){
251  modelFile = vpIoTools::createFilePath(opt_ipath, modelFileCao);
252  }
253  else{
254 #ifdef VISP_HAVE_COIN3D
255  modelFile = vpIoTools::createFilePath(opt_ipath, modelFileWrl);
256 #else
257  std::cerr << "Coin is not detected in ViSP. Use the .cao model instead." << std::endl;
258  modelFile = vpIoTools::createFilePath(opt_ipath, modelFileCao);
259 #endif
260  }
261  }
262  else{
263  if(cao3DModel){
264  modelFile = vpIoTools::createFilePath(env_ipath, modelFileCao);
265  }
266  else{
267 #ifdef VISP_HAVE_COIN3D
268  modelFile = vpIoTools::createFilePath(env_ipath, modelFileWrl);
269 #else
270  std::cerr << "Coin is not detected in ViSP. Use the .cao model instead." << std::endl;
271  modelFile = vpIoTools::createFilePath(env_ipath, modelFileCao);
272 #endif
273  }
274  }
275  }
276 
277  if (!opt_initFile.empty())
278  initFile = opt_initFile;
279  else if (!opt_ipath.empty())
280  initFile = vpIoTools::createFilePath(opt_ipath, "ViSP-images/mbt/cube");
281  else
282  initFile = vpIoTools::createFilePath(env_ipath, "ViSP-images/mbt/cube");
283 
284  vpImage<unsigned char> I1, I2;
285  vpVideoReader reader;
286 
287  reader.setFileName(ipath);
288  try{
289  reader.open(I1);
290  I2 = I1;
291  }catch(...){
292  std::cout << "Cannot open sequence: " << ipath << std::endl;
293  return -1;
294  }
295 
296  reader.acquire(I1);
297  I2 = I1;
298 
299  // initialise a display
300 #if defined VISP_HAVE_X11
301  vpDisplayX display1, display2;
302 #elif defined VISP_HAVE_GDI
303  vpDisplayGDI display1, display2;
304 #elif defined VISP_HAVE_OPENCV
305  vpDisplayOpenCV display1, display2;
306 #elif defined VISP_HAVE_D3D9
307  vpDisplayD3D display1, display2;
308 #elif defined VISP_HAVE_GTK
309  vpDisplayGTK display1, display2;
310 #else
311  opt_display = false;
312 #endif
313  if (opt_display)
314  {
315 #if (defined VISP_HAVE_DISPLAY)
318  display1.init(I1, 100, 100, "Test tracking (Left)");
319  display2.init(I2, (int) I1.getWidth()/vpDisplay::getDownScalingFactor(I1)+110, 100, "Test tracking (Right)");
320 #endif
321  vpDisplay::display(I1);
322  vpDisplay::display(I2);
323  vpDisplay::flush(I1);
324  vpDisplay::flush(I2);
325  }
326 
327  vpMbKltMultiTracker tracker(2);
328  vpHomogeneousMatrix c1Mo, c2Mo;
329 
330  // Load tracker config file (camera parameters and moving edge settings)
331  vpCameraParameters cam1, cam2;
332 #if defined (VISP_HAVE_XML2)
333  // From the xml file
334  tracker.loadConfigFile(configFile, configFile);
335 #else
336  // By setting the parameters:
337  cam1.initPersProjWithoutDistortion(547, 542, 338, 234);
338  cam2.initPersProjWithoutDistortion(547, 542, 338, 234);
339 
340  vpKltOpencv klt;
341  klt.setMaxFeatures(10000);
342  klt.setWindowSize(5);
343  klt.setQuality(0.01);
344  klt.setMinDistance(5);
345  klt.setHarrisFreeParameter(0.01);
346  klt.setBlockSize(3);
347  klt.setPyramidLevels(3);
348 
349  tracker.setCameraParameters(cam1, cam2);
350  tracker.setKltOpencv(klt);
351  tracker.setAngleAppear( vpMath::rad(65) );
352  tracker.setAngleDisappear( vpMath::rad(75) );
353  tracker.setMaskBorder(5);
354 
355  // Specify the clipping to use
356  tracker.setNearClippingDistance(0.01);
357  tracker.setFarClippingDistance(0.90);
358  tracker.setClipping(tracker.getClipping() | vpMbtPolygon::FOV_CLIPPING);
359  // tracker.setClipping(tracker.getClipping() | vpMbtPolygon::LEFT_CLIPPING | vpMbtPolygon::RIGHT_CLIPPING | vpMbtPolygon::UP_CLIPPING | vpMbtPolygon::DOWN_CLIPPING); // Equivalent to FOV_CLIPPING
360 #endif
361 
362  // Display the klt points
363  tracker.setDisplayFeatures(displayKltPoints);
364 
365  // Tells if the tracker has to use Ogre3D for visibility tests
366  tracker.setOgreVisibilityTest(useOgre);
367  if (useOgre)
368  tracker.setOgreShowConfigDialog(showOgreConfigDialog);
369 
370  // Tells if the tracker has to use the scanline visibility tests
371  tracker.setScanLineVisibilityTest(useScanline);
372 
373  // Tells if the tracker has to compute the covariance matrix
374  tracker.setCovarianceComputation(computeCovariance);
375 
376  // Retrieve the camera parameters from the tracker
377  tracker.getCameraParameters(cam1, cam2);
378 
379  // Loop to position the cube
380  if (opt_display && opt_click_allowed)
381  {
382  while(!vpDisplay::getClick(I1,false)){
383  vpDisplay::display(I1);
384  vpDisplay::displayText(I1, 15, 10, "click after positioning the object", vpColor::red);
385  vpDisplay::flush(I1);
386  vpTime::wait(100);
387  }
388  }
389 
390  // Load the 3D model (either a vrml file or a .cao file)
391  tracker.loadModel(modelFile);
392 
393  // Initialise the tracker by clicking on the image
394  // This function looks for
395  // - a ./cube/cube.init file that defines the 3d coordinates (in meter, in the object basis) of the points used for the initialisation
396  // - a ./cube/cube.ppm file to display where the user have to click (optionnal, set by the third parameter)
397  if (opt_display && opt_click_allowed)
398  {
399  tracker.initClick(I1, I2, initFile, initFile, true);
400  tracker.getPose(c1Mo, c2Mo);
401  // display the 3D model at the given pose
402  tracker.display(I1, I2,c1Mo, c2Mo, cam1, cam2, vpColor::red);
403  }
404  else
405  {
406  vpHomogeneousMatrix c1Moi(0.02044769891, 0.1101505452, 0.5078963719, 2.063603907, 1.110231561, -0.4392789872);
407  vpHomogeneousMatrix c2Moi(0.02044769891, 0.1101505452, 0.5078963719, 2.063603907, 1.110231561, -0.4392789872);
408  tracker.initFromPose(I1, I2, c1Moi, c2Moi);
409  }
410 
411  //track the model
412  tracker.track(I1, I2);
413  tracker.getPose(c1Mo, c2Mo);
414 
415  if (opt_display) {
416  vpDisplay::flush(I1);
417  vpDisplay::flush(I2);
418  }
419 
420  while (!reader.end())
421  {
422  // acquire a new image
423  reader.acquire(I1);
424  I2 = I1;
425  // display the image
426  if (opt_display) {
427  vpDisplay::display(I1);
428  vpDisplay::display(I2);
429  }
430 
431  // Test to reset the tracker
432  if (reader.getFrameIndex() == reader.getFirstFrameIndex() + 10) {
433  std::cout << "----------Test reset tracker----------" << std::endl;
434  if (opt_display) {
435  vpDisplay::display(I1);
436  vpDisplay::display(I2);
437  }
438  tracker.resetTracker();
439 #if defined (VISP_HAVE_XML2)
440  tracker.loadConfigFile(configFile, configFile);
441 #else
442  // By setting the parameters:
443  cam1.initPersProjWithoutDistortion(547, 542, 338, 234);
444  cam2.initPersProjWithoutDistortion(547, 542, 338, 234);
445 
446  vpKltOpencv klt;
447  klt.setMaxFeatures(10000);
448  klt.setWindowSize(5);
449  klt.setQuality(0.01);
450  klt.setMinDistance(5);
451  klt.setHarrisFreeParameter(0.01);
452  klt.setBlockSize(3);
453  klt.setPyramidLevels(3);
454 
455  tracker.setCameraParameters(cam1, cam2);
456  tracker.setKltOpencv(klt);
457  tracker.setAngleAppear( vpMath::rad(65) );
458  tracker.setAngleDisappear( vpMath::rad(75) );
459  tracker.setMaskBorder(5);
460 
461  // Specify the clipping to use
462  tracker.setNearClippingDistance(0.01);
463  tracker.setFarClippingDistance(0.90);
464  tracker.setClipping(tracker.getClipping() | vpMbtPolygon::FOV_CLIPPING);
465  // tracker.setClipping(tracker.getClipping() | vpMbtPolygon::LEFT_CLIPPING | vpMbtPolygon::RIGHT_CLIPPING | vpMbtPolygon::UP_CLIPPING | vpMbtPolygon::DOWN_CLIPPING); // Equivalent to FOV_CLIPPING
466 #endif
467  tracker.loadModel(modelFile);
468  tracker.setCameraParameters(cam1, cam2);
469  tracker.setOgreVisibilityTest(useOgre);
470  tracker.setScanLineVisibilityTest(useScanline);
471  tracker.setCovarianceComputation(computeCovariance);
472  tracker.initFromPose(I1, I2, c1Mo, c2Mo);
473  }
474 
475  // Test to set an initial pose
476  if (reader.getFrameIndex() == reader.getFirstFrameIndex() + 50) {
477  c1Mo.buildFrom(0.0439540832, 0.0845870108, 0.5477322481, 2.179498458, 0.8611798108, -0.3491961946);
478  c2Mo.buildFrom(0.0439540832, 0.0845870108, 0.5477322481, 2.179498458, 0.8611798108, -0.3491961946);
479  std::cout << "Test set pose" << std::endl;
480  tracker.setPose(I1, I2, c1Mo, c2Mo);
481  }
482 
483  // track the object: stop tracking from frame 40 to 50
484  if (reader.getFrameIndex() - reader.getFirstFrameIndex() < 40 || reader.getFrameIndex() - reader.getFirstFrameIndex() >= 50) {
485  tracker.track(I1, I2);
486  tracker.getPose(c1Mo, c2Mo);
487  if (opt_display) {
488  // display the 3D model
489  tracker.display(I1, I2, c1Mo, c2Mo, cam1, cam2, vpColor::darkRed);
490  // display the frame
491  vpDisplay::displayFrame (I1, c1Mo, cam1, 0.05);
492  vpDisplay::displayFrame (I2, c2Mo, cam2, 0.05);
493  }
494  }
495 
496  if (opt_click_allowed) {
497  vpDisplay::displayText(I1, 10, 10, "Click to quit", vpColor::red);
498  if (vpDisplay::getClick(I1, false)) {
499  quit = true;
500  break;
501  }
502  }
503 
504  if(computeCovariance) {
505  std::cout << "Covariance matrix: \n" << tracker.getCovarianceMatrix() << std::endl << std::endl;
506  }
507 
508  vpDisplay::flush(I1);
509  vpDisplay::flush(I2);
510  }
511  if (opt_click_allowed && !quit) {
513  }
514 
515  reader.close();
516 
517 #if defined (VISP_HAVE_XML2)
518  // Cleanup memory allocated by xml library used to parse the xml config file in vpMbKltTracker::loadConfigFile()
520 #endif
521 
522 #if defined(VISP_HAVE_COIN3D) && (COIN_MAJOR_VERSION == 2 || COIN_MAJOR_VERSION == 3)
523  // Cleanup memory allocated by Coin library used to load a vrml model in vpMbKltTracker::loadModel()
524  // We clean only if Coin was used.
525  if(! cao3DModel)
526  SoDB::finish();
527 #endif
528 
529  return 0;
530  }
531  catch(vpException &e) {
532  std::cout << "Catch an exception: " << e << std::endl;
533  return 1;
534  }
535 }
536 
537 #else
538 
539 int main()
540 {
541  std::cout << "visp_mbt, visp_gui modules and OpenCV are required to run this example." << std::endl;
542  return 0;
543 
544 }
545 
546 #endif
VISP_EXPORT int wait(double t0, double t)
Definition: vpTime.cpp:157
long getFrameIndex() const
long getFirstFrameIndex() const
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1157
void setHarrisFreeParameter(double harris_k)
unsigned int getWidth() const
Definition: vpImage.h:226
Implementation of an homogeneous matrix and operations on such kind of matrices.
virtual void setDownScalingFactor(unsigned int scale)
Definition: vpDisplay.cpp:248
static const vpColor darkRed
Definition: vpColor.h:164
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
void setMaxFeatures(const int maxCount)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:153
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
void setMinDistance(double minDistance)
error that can be emited by ViSP classes.
Definition: vpException.h:73
static void flush(const vpImage< unsigned char > &I)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:76
static const vpColor red
Definition: vpColor.h:163
void setQuality(double qualityLevel)
void initPersProjWithoutDistortion(const double px, const double py, const double u0, const double v0)
void open(vpImage< vpRGBa > &I)
Display for windows using Direct3D 3rd party. Thus to enable this class Direct3D should be installed...
Definition: vpDisplayD3D.h:107
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1366
static void display(const vpImage< unsigned char > &I)
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Generic class defining intrinsic camera parameters.
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:138
void acquire(vpImage< vpRGBa > &I)
void setFileName(const char *filename)
void setPyramidLevels(const int pyrMaxLevel)
void buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
static double rad(double deg)
Definition: vpMath.h:104
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, vpImagePoint offset=vpImagePoint(0, 0))
static void cleanup()
Definition: vpXmlParser.h:308
void setWindowSize(const int winSize)
unsigned int getDownScalingFactor()
Definition: vpDisplay.h:214
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV. Thus to enable this ...
Definition: vpKltOpencv.h:76
void setBlockSize(const int blockSize)
Model based stereo (or more) tracker using only KLT.