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