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