Visual Servoing Platform  version 3.0.0
poseVirtualVS.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 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  * Pose computation on an object made of dots.
32  * reading of PGM image
33  * Display image using either the X11 or GTK or GDI display
34  * track 4 dots (vpDots) in the image
35  * compute the pose
36  *
37  * Authors:
38  * Eric Marchand
39  * Anthony Saunier
40  *
41  *****************************************************************************/
62 #include <visp3/core/vpDebug.h>
63 #include <visp3/core/vpConfig.h>
64 #include <stdlib.h>
65 #include <stdio.h>
66 #include <sstream>
67 #include <iomanip>
68 #if (defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
69 
70 #include <visp3/core/vpImage.h>
71 #include <visp3/io/vpImageIo.h>
72 #include <visp3/core/vpImagePoint.h>
73 
74 #include <visp3/gui/vpDisplayX.h>
75 #include <visp3/gui/vpDisplayGTK.h>
76 #include <visp3/gui/vpDisplayGDI.h>
77 #include <visp3/gui/vpDisplayOpenCV.h>
78 
79 #include <visp3/vision/vpPose.h>
80 #include <visp3/blob/vpDot.h>
81 #include <visp3/core/vpPixelMeterConversion.h>
82 #include <visp3/io/vpParseArgv.h>
83 #include <visp3/core/vpIoTools.h>
84 
85 
86 // List of allowed command line options
87 #define GETOPTARGS "cdi:p:hf:n:s:"
88 
89 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
90  unsigned first, unsigned nimages, unsigned step);
91 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath,
92  unsigned &first, unsigned &nimages, unsigned &step,
93  bool &click_allowed, bool &display);
94 
108 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
109  unsigned first, unsigned nimages, unsigned step)
110 {
111  fprintf(stdout, "\n\
112 Test dot tracking.\n\
113 \n\
114 SYNOPSIS\n\
115  %s [-i <input image path>] [-p <personal image path>]\n\
116  [-f <first image>] [-n <number of images>] [-s <step>][-c] [-d] [-h]\n", name);
117 
118  fprintf(stdout, "\n\
119 OPTIONS: Default\n\
120  -i <input image path> %s\n\
121  Set image input path.\n\
122  From this path read images \n\
123  \"ViSP-images/cube/image.%%04d.pgm\"\n\
124  Setting the VISP_INPUT_IMAGE_PATH environment\n\
125  variable produces the same behaviour than using\n\
126  this option.\n\
127  \n\
128  -p <personal image path> %s\n\
129  Specify a personal sequence containing images \n\
130  to process.\n\
131  By image sequence, we mean one file per image.\n\
132  The following image file formats PNM (PGM P5, PPM P6)\n\
133  are supported. The format is selected by analysing \n\
134  the filename extension.\n\
135  Example : \"/Temp/ViSP-images/cube/image.%%04d.pgm\"\n\
136  %%04d is for the image numbering.\n\
137  \n\
138  -f <first image> %u\n\
139  First image number of the sequence.\n\
140  \n\
141  -n <number of images> %u\n\
142  Number of images to load from the sequence.\n\
143  \n\
144  -s <step> %u\n\
145  Step between two images.\n\
146 \n\
147  -c\n\
148  Disable the mouse click. Useful to automaze the \n\
149  execution of this program without humain intervention.\n\
150 \n\
151  -d \n\
152  Turn off the display.\n\
153 \n\
154  -h\n\
155  Print the help.\n",
156  ipath.c_str(),ppath.c_str(), first, nimages, step);
157 
158  if (badparam)
159  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
160 }
181 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath,
182  unsigned &first, unsigned &nimages, unsigned &step,
183  bool &click_allowed, bool &display)
184 {
185  const char *optarg_;
186  int c;
187  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
188 
189  switch (c) {
190  case 'c': click_allowed = false; break;
191  case 'd': display = false; break;
192  case 'i': ipath = optarg_; break;
193  case 'p': ppath = optarg_; break;
194  case 'f': first = (unsigned) atoi(optarg_); break;
195  case 'n': nimages = (unsigned) atoi(optarg_); break;
196  case 's': step = (unsigned) atoi(optarg_); break;
197  case 'h': usage(argv[0], NULL, ipath, ppath, first, nimages, step); return false; break;
198 
199  default:
200  usage(argv[0], optarg_, ipath, ppath, first, nimages, step);
201  return false; break;
202  }
203  }
204 
205  if ((c == 1) || (c == -1)) {
206  // standalone param or error
207  usage(argv[0], NULL, ipath, ppath, first, nimages, step);
208  std::cerr << "ERROR: " << std::endl;
209  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
210  return false;
211  }
212 
213  return true;
214 }
215 
216 
217 
218 
219 int
220 main(int argc, const char** argv)
221 {
222  try {
223  std::string env_ipath;
224  std::string opt_ipath;
225  std::string ipath;
226  std::string opt_ppath;
227  std::string dirname;
228  std::string filename;
229  unsigned opt_first = 0;
230  unsigned opt_nimages = 80;
231  unsigned opt_step = 1;
232  bool opt_click_allowed = true;
233  bool opt_display = true;
234 
235  int i ;
236 
237  std::cout << "-------------------------------------------------------" << std::endl ;
238  std::cout << " poseVirtualVS.cpp" <<std::endl << std::endl ;
239 
240  std::cout << " Example of dots tracking in an image sequence and pose computation" << std::endl ;
241  std::cout << "-------------------------------------------------------" << std::endl ;
242  std::cout << std::endl ;
243 
244  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
245  env_ipath = vpIoTools::getViSPImagesDataPath();
246 
247  // Set the default input path
248  if (! env_ipath.empty())
249  ipath = env_ipath;
250 
251  // Read the command line options
252  if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_first, opt_nimages, opt_step, opt_click_allowed, opt_display) == false) {
253  exit (-1);
254  }
255 
256  // Get the option values
257  if (!opt_ipath.empty())
258  ipath = opt_ipath;
259 
260  // Compare ipath and env_ipath. If they differ, we take into account
261  // the input path comming from the command line option
262  if (opt_ipath.empty() && opt_ppath.empty()) {
263  if (ipath != env_ipath) {
264  std::cout << std::endl
265  << "WARNING: " << std::endl;
266  std::cout << " Since -i <visp image path=" << ipath << "> "
267  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
268  << " we skip the environment variable." << std::endl;
269  }
270  }
271  // Test if an input path is set
272  if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty()){
273  usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_nimages, opt_step);
274  std::cerr << std::endl
275  << "ERROR:" << std::endl;
276  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
277  << std::endl
278  << " environment variable to specify the location of the " << std::endl
279  << " image path where test images are located." << std::endl
280  << " Use -p <personal image path> option if you want to "<< std::endl
281  << " use personal images" <<std::endl << std::endl;
282  exit(-1);
283  }
284 
285 
286 
287 
288  // Declare an image, this is a gray level image (unsigned char)
289  // it size is not defined yet, it will be defined when the image will
290  // read on the disk
292 
293  unsigned iter = opt_first ;
294  std::ostringstream s;
295  char cfilename[FILENAME_MAX];
296 
297  if (opt_ppath.empty()){
298 
299  // Warning :
300  // the image sequence is not provided with the ViSP package
301  // therefore the program will return you an error :
302  // !! vpImageIoPnm.cpp: readPGM(#210) :couldn't read file /ViSP-images/cube/image.0001.pgm
303  // !! poseExample.cpp: main(#95) :Error while reading the image
304  // terminate called after throwing an instance of 'vpImageException'
305  //
306  // The sequence is available on the visp www site
307  // http://www.irisa.fr/lagadic/visp/visp.html
308  // in the download section. It is named "ViSP-images-x.y.z.tar.gz"
309 
310  // directory name
311  dirname = vpIoTools::createFilePath(ipath, "ViSP-images/cube");
312 
313  // Build the name of the image file
314 
315  s.setf(std::ios::right, std::ios::adjustfield);
316  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
317  filename = vpIoTools::createFilePath(dirname, s.str());
318  }
319  else {
320 
321  sprintf(cfilename, opt_ppath.c_str(), iter) ;
322  filename = cfilename;
323  }
324 
325  // define the vpDot structure, here 4 dots will tracked
326  vpDot d[4] ;
327 
328  for (i=0 ; i < 4 ; i++)
329  {
330  // by using setGraphics, we request to see the all the pixel of the dot
331  // in green on the screen.
332  // It uses the overlay image plane.
333  // The default of this setting is that it is time consumming
334 
335  if (opt_display) {
336  d[i].setGraphics(true) ;
337  }
338  else {
339  d[i].setGraphics(false) ;
340  }
341  }
342 
343  // Read the PGM image named "s" on the disk, and put the bitmap into the
344  // image structure I.
345  // I is initialized to the correct size
346  //
347  // exception readPGM may throw various exception if, for example,
348  // the file does not exist, or if the memory cannot be allocated
349  try{
350  vpImageIo::read(I,filename) ;
351  }
352  catch(...)
353  {
354  // an exception is throwned if an exception from readPGM has been catched
355  // here this will result in the end of the program
356  // Note that another error message has been printed from readPGM
357  // to give more information about the error
358  if (opt_ppath.empty()) {
359  std::cerr << std::endl
360  << "ERROR:" << std::endl;
361  std::cerr << " Cannot read " << filename << std::endl;
362  std::cerr << " Check your -i " << ipath << " option, " << std::endl
363  << " or VISP_INPUT_IMAGE_PATH environment variable"
364  << std::endl;
365  }
366  else {
367  std::cerr << std::endl
368  << "ERROR:" << std::endl;
369  std::cerr << " Cannot read " << filename << std::endl;
370  std::cerr << " or your -p " << opt_ppath << " option " <<std::endl
371  << std::endl;
372  }
373  exit(-1);
374 
375  }
376 
377  // We open a window using either the X11 or GTK or GDI window manager
378  // it will be located in 100,100 and titled "tracking using vpDot"
379  // its size is automatically defined by the image (I) size
380 #if defined VISP_HAVE_X11
381  vpDisplayX display;
382 #elif defined VISP_HAVE_GTK
383  vpDisplayGTK display;
384 #elif defined VISP_HAVE_GDI
385  vpDisplayGDI display;
386 #elif defined VISP_HAVE_OPENCV
387  vpDisplayOpenCV display;
388 #endif
389  if (opt_display) {
390  // Display size is automatically defined by the image (I) size
391  display.init(I,100,100,"tracking using vpDot");
392  // display the image
393  // The image class has a member that specify a pointer toward
394  // the display that has been initialized in the display declaration
395  // therefore is is no longuer necessary to make a reference to the
396  // display variable.
397  vpDisplay::display(I) ;
398  //Flush the display
399  vpDisplay::flush(I) ;
400  }
401 
402  vpImagePoint cog[4]; // Center of gravity of the dot
403  if (opt_display && opt_click_allowed) {
404  // dot coordinates (u,v) = (column,row)
405  std::cout << "Click the four white dots on the object corner clockwise"
406  << std::endl ;
407  for (i=0 ; i < 4 ; i++)
408  {
409  // tracking is initalized if no other parameters are given
410  // to the iniTracking(..) method a right mouse click on the
411  // dot is expected dot location can also be specified
412  // explicitely in the initTracking method :
413  // d.initTracking(I,ip) where ip is the image point from
414  // where the dot need to be searched.
415 
416  d[i].initTracking(I) ;
417  // track the dot and returns its coordinates in the image
418  // results are given in float since many many are usually considered
419  //
420  // an expcetion is thrown by the track method if
421  // - dot is lost
422  // - the number of pixel is too small
423  // - too many pixels are detected (this is usual when a "big" specularity
424  // occurs. The threshold can be modified using the
425  // setMaxDotSize() method
426  d[i].track(I, cog[i]) ;
427  vpDisplay::flush(I) ;
428  }
429  }
430  else{
431  cog[0].set_u( 194 );
432  cog[0].set_v( 88 );
433  d[0].initTracking(I, cog[0] );
434  d[0].track(I, cog[0]);
435  vpDisplay::flush(I) ;
436 
437  cog[1].set_u( 225 );
438  cog[1].set_v( 84 );
439  d[1].initTracking(I, cog[1]);
440  d[1].track(I, cog[1]);
441  vpDisplay::flush(I) ;
442 
443  cog[2].set_u( 242 );
444  cog[2].set_v( 114 );
445  d[2].initTracking(I, cog[2]);
446  d[2].track(I, cog[2]);
447  vpDisplay::flush(I) ;
448 
449  cog[3].set_u( 212 );
450  cog[3].set_v( 131 );
451  d[3].initTracking(I, cog[3]);
452  d[3].track(I, cog[3]);
453  vpDisplay::flush(I) ;
454  }
455 
456  if (opt_display)
457  {
458 
459  // display a red cross (size 10) in the image at the dot center
460  // of gravity location
461  //
462  // WARNING
463  // in the vpDisplay class member's when pixel coordinates
464  // are considered the first element is the row index and the second
465  // is the column index:
466  // vpDisplay::displayCross(Image, row index, column index, size, color)
467  // therefore u and v are inverted wrt to the vpDot specification
468  // Alternatively, to avoid this problem another set of member have
469  // been defined in the vpDisplay class.
470  // If the method name is postfixe with _uv the specification is :
471  // vpDisplay::displayCross_uv(Image, column index, row index, size, color)
472 
473  for (i=0 ; i < 4 ; i++)
474  vpDisplay::displayCross(I, cog[i], 10, vpColor::red) ;
475 
476  // flush the X11 buffer
477  vpDisplay::flush(I) ;
478  }
479 
480  // --------------------------------------------------------
481  // Now wil compute the pose
482  //
483 
484  // The pose will be contained in an homogeneous matrix cMo
485  vpHomogeneousMatrix cMo ;
486 
487 
488  // We need a structure that content both the 3D coordinates of the point
489  // in the object frame and the 2D coordinates of the point expressed in meter
490  // the vpPoint class is ok for that
491  vpPoint P[4] ;
492 
493  // The vpPose class mainly contents a list of vpPoint (that is (X,Y,Z, x, y) )
494  vpPose pose ;
495  // the list of point is cleared (if that's not done before)
496  pose.clearPoint() ;
497 
498  // we set the 3D points coordinates (in meter !) in the object/world frame
499  double L=0.04 ;
500  P[0].setWorldCoordinates(-L,-L, 0 ) ; // (X,Y,Z)
501  P[1].setWorldCoordinates(L,-L, 0 ) ;
502  P[2].setWorldCoordinates(L,L, 0 ) ;
503  P[3].setWorldCoordinates(-L,L, 0 ) ;
504 
505 
506  // set the camera intrinsic parameters
507  // see more details about the model in vpCameraParameters
508  double px = 600 ;
509  double py = 600 ;
510  double u0 = 192 ;
511  double v0 = 144 ;
512  vpCameraParameters cam(px,py,u0,v0) ;
513 
514  // pixel-> meter conversion
515  for (i=0 ; i < 4 ; i++)
516  {
517  // u[i]. v[i] are expressed in pixel
518  // conversion in meter is achieved using
519  // x = (u-u0)/px
520  // y = (v-v0)/py
521  // where px, py, u0, v0 are the intrinsic camera parameters
522  double x=0, y=0;
523  vpPixelMeterConversion::convertPoint(cam, cog[i], x,y) ;
524  P[i].set_x(x) ;
525  P[i].set_y(y) ;
526  }
527 
528 
529  // The pose structure is build, we put in the point list the set of point
530  // here both 2D and 3D world coordinates are known
531  for (i=0 ; i < 4 ; i++)
532  {
533  pose.addPoint(P[i]) ; // and added to the pose computation point list
534  }
535 
536  // compute the initial pose using Dementhon method followed by a non linear
537  // minimisation method
538 
539  // Pose by Lagrange it provides an initialization of the pose
540  pose.computePose(vpPose::LAGRANGE, cMo) ;
541  // the pose is now refined using the virtual visual servoing approach
542  // Warning: cMo needs to be initialized otherwise it may diverge
543  pose.computePose(vpPose::VIRTUAL_VS, cMo) ;
544  if( opt_display ){
545  // display the compute pose
546  pose.display(I,cMo,cam, 0.05, vpColor::red) ;
547  vpDisplay::flush(I) ;
548  }
549 
550  // Covariance Matrix Computation
551  // Uncomment if you want to compute the covariance matrix.
552  // pose.setCovarianceComputation(true); //Important if you want tracker.getCovarianceMatrix() to work.
553 
554  unsigned niter = 0;
555  // this is the loop over the image sequence
556  while (iter < opt_nimages)
557  {
558  // set the new image name
559 
560  if (opt_ppath.empty()){
561  s.str("");
562  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
563  filename = vpIoTools::createFilePath(dirname, s.str());
564  }
565  else {
566  sprintf( cfilename, opt_ppath.c_str(), iter) ;
567  filename = cfilename ;
568  }
569 
570  // read the image
571  vpImageIo::read(I,filename) ;
572  if (opt_display){
573  // Display the image
574  vpDisplay::display(I) ;
575  //Flush the display
576  vpDisplay::flush(I) ;
577 
578  }
579  // kill the point list
580  pose.clearPoint() ;
581 
582  // track the dot
583  for (i=0 ; i < 4 ; i++)
584  {
585  // track the point
586  d[i].track(I, cog[i]) ;
587  if (opt_display){
588  // display point location
589  vpDisplay::displayCross(I, cog[i], 10,vpColor::red) ;
590  }
591  // pixel->meter conversion
592  {
593  double x=0, y=0;
594  vpPixelMeterConversion::convertPoint(cam, cog[i], x, y) ;
595  P[i].set_x(x) ;
596  P[i].set_y(y) ;
597  }
598 
599  // and added to the pose computation point list
600  pose.addPoint(P[i]) ;
601  }
602  // the pose structure has been updated
603 
604 
605  // the pose is now updated using the virtual visual servoing approach
606  // Dementhon or lagrange is no longuer necessary, pose at the
607  // previous iteration is sufficient
608  pose.computePose(vpPose::VIRTUAL_VS, cMo) ;
609  if (opt_display) {
610  // display the compute pose
611  pose.display(I,cMo,cam, 0.05, vpColor::red) ;
612 
613  vpDisplay::flush(I) ;
614  }
615 
616  // Covariance Matrix Display
617  // Uncomment if you want to print the covariance matrix.
618  // Make sure pose.setCovarianceComputation(true) has been called (uncomment below).
619  // std::cout << pose.getCovarianceMatrix() << std::endl << std::endl;
620 
621  niter++ ;
622 
623  iter += opt_step ;
624  }
625  return 0;
626  }
627  catch(vpException e) {
628  std::cout << "Catch a ViSP exception: " << e << std::endl;
629  return 1;
630  }
631 }
632 #else
633 int
634 main()
635 {
636  vpERROR_TRACE("You do not have X11, GTK, GDI or OpenCV functionalities to display images...");
637 }
638 
639 #endif
640 
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1091
Implementation of an homogeneous matrix and operations on such kind of matrices.
#define vpERROR_TRACE
Definition: vpDebug.h:391
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
Define the X11 console to display images.
Definition: vpDisplayX.h:148
void track(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:800
error that can be emited by ViSP classes.
Definition: vpException.h:73
void set_x(const double x)
Set the point x coordinate in the image plane.
Definition: vpPoint.cpp:496
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Point coordinates conversion from pixel coordinates to normalized coordinates in meter...
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:2233
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:76
static const vpColor red
Definition: vpColor.h:163
Class that defines what is a point.
Definition: vpPoint.h:59
static void display(vpImage< unsigned char > &I, vpHomogeneousMatrix &cMo, vpCameraParameters &cam, double size, vpColor col=vpColor::none)
Definition: vpPose.cpp:585
void set_u(const double u)
Definition: vpImagePoint.h:212
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1265
bool computePose(vpPoseMethodType methode, vpHomogeneousMatrix &cMo, bool(*func)(vpHomogeneousMatrix *)=NULL)
compute the pose for a given method
Definition: vpPose.cpp:382
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:206
The vpDisplayOpenCV allows to display image using the opencv library.
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
void set_v(const double v)
Definition: vpImagePoint.h:223
Class used for pose computation from N points (pose from point only).
Definition: vpPose.h:74
Generic class defining intrinsic camera parameters.
void set_y(const double y)
Set the point y coordinate in the image plane.
Definition: vpPoint.cpp:498
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:141
void setWorldCoordinates(const double oX, const double oY, const double oZ)
Definition: vpPoint.cpp:111
void setGraphics(const bool activate)
Definition: vpDot.h:351
This tracker is meant to track a dot (connected pixels with same gray level) on a vpImage...
Definition: vpDot.h:115
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
static void read(vpImage< unsigned char > &I, const char *filename)
Definition: vpImageIo.cpp:274
void addPoint(const vpPoint &P)
Add a new point in this array.
Definition: vpPose.cpp:151
void initTracking(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:654
void clearPoint()
suppress all the point in the array of point
Definition: vpPose.cpp:129