ViSP  2.8.0
poseVirtualVS.cpp
1 /****************************************************************************
2  *
3  * $Id: poseVirtualVS.cpp 4323 2013-07-18 09:24:01Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 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 
105 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath,
106  unsigned first, unsigned nimages, unsigned step)
107 {
108  fprintf(stdout, "\n\
109 Test dot tracking.\n\
110 \n\
111 SYNOPSIS\n\
112  %s [-i <input image path>] [-p <personal image path>]\n\
113  [-f <first image>] [-n <number of images>] [-s <step>][-c] [-d] [-h]\n", name);
114 
115  fprintf(stdout, "\n\
116 OPTIONS: Default\n\
117  -i <input image path> %s\n\
118  Set image input path.\n\
119  From this path read images \n\
120  \"ViSP-images/cube/image.%%04d.pgm\"\n\
121  Setting the VISP_INPUT_IMAGE_PATH environment\n\
122  variable produces the same behaviour than using\n\
123  this option.\n\
124  \n\
125  -p <personal image path> %s\n\
126  Specify a personal sequence containing images \n\
127  to process.\n\
128  By image sequence, we mean one file per image.\n\
129  The following image file formats PNM (PGM P5, PPM P6)\n\
130  are supported. The format is selected by analysing \n\
131  the filename extension.\n\
132  Example : \"/Temp/ViSP-images/cube/image.%%04d.pgm\"\n\
133  %%04d is for the image numbering.\n\
134  \n\
135  -f <first image> %u\n\
136  First image number of the sequence.\n\
137  \n\
138  -n <number of images> %u\n\
139  Number of images to load from the sequence.\n\
140  \n\
141  -s <step> %u\n\
142  Step between two images.\n\
143 \n\
144  -c\n\
145  Disable the mouse click. Useful to automaze the \n\
146  execution of this program without humain intervention.\n\
147 \n\
148  -d \n\
149  Turn off the display.\n\
150 \n\
151  -h\n\
152  Print the help.\n",
153  ipath.c_str(),ppath.c_str(), first, nimages, step);
154 
155  if (badparam)
156  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
157 }
178 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath,
179  unsigned &first, unsigned &nimages, unsigned &step,
180  bool &click_allowed, bool &display)
181 {
182  const char *optarg;
183  int c;
184  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg)) > 1) {
185 
186  switch (c) {
187  case 'c': click_allowed = false; break;
188  case 'd': display = false; break;
189  case 'i': ipath = optarg; break;
190  case 'p': ppath = optarg; break;
191  case 'f': first = (unsigned) atoi(optarg); break;
192  case 'n': nimages = (unsigned) atoi(optarg); break;
193  case 's': step = (unsigned) atoi(optarg); break;
194  case 'h': usage(argv[0], NULL, ipath, ppath, first, nimages, step); return false; break;
195 
196  default:
197  usage(argv[0], optarg, ipath, ppath, first, nimages, step);
198  return false; break;
199  }
200  }
201 
202  if ((c == 1) || (c == -1)) {
203  // standalone param or error
204  usage(argv[0], NULL, ipath, ppath, first, nimages, step);
205  std::cerr << "ERROR: " << std::endl;
206  std::cerr << " Bad argument " << optarg << std::endl << std::endl;
207  return false;
208  }
209 
210  return true;
211 }
212 
213 
214 
215 
216 int
217 main(int argc, const char** argv)
218 {
219  std::string env_ipath;
220  std::string opt_ipath;
221  std::string ipath;
222  std::string opt_ppath;
223  std::string dirname;
224  std::string filename;
225  unsigned opt_first = 0;
226  unsigned opt_nimages = 80;
227  unsigned opt_step = 1;
228  bool opt_click_allowed = true;
229  bool opt_display = true;
230 
231 
232  int i ;
233 
234  std::cout << "-------------------------------------------------------" << std::endl ;
235  std::cout << " poseVirtualVS.cpp" <<std::endl << std::endl ;
236 
237  std::cout << " Example of dots tracking in an image sequence and pose computation" << std::endl ;
238  std::cout << "-------------------------------------------------------" << std::endl ;
239  std::cout << std::endl ;
240 
241  // Get the VISP_IMAGE_PATH environment variable value
242  char *ptenv = getenv("VISP_INPUT_IMAGE_PATH");
243  if (ptenv != NULL)
244  env_ipath = ptenv;
245 
246  // Set the default input path
247  if (! env_ipath.empty())
248  ipath = env_ipath;
249 
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 = ipath + vpIoTools::path("/ViSP-images/cube/");
312 
313 
314  // Build the name of the image file
315 
316  s.setf(std::ios::right, std::ios::adjustfield);
317  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
318  filename = dirname + s.str();
319  }
320  else {
321 
322  sprintf(cfilename, opt_ppath.c_str(), iter) ;
323  filename = cfilename;
324  }
325 
326  // define the vpDot structure, here 4 dots will tracked
327  vpDot d[4] ;
328 
329  for (i=0 ; i < 4 ; i++)
330  {
331  // by using setGraphics, we request to see the all the pixel of the dot
332  // in green on the screen.
333  // It uses the overlay image plane.
334  // The default of this setting is that it is time consumming
335 
336  if (opt_display) {
337  d[i].setGraphics(true) ;
338  }
339  else {
340  d[i].setGraphics(false) ;
341  }
342  }
343 
344  // Read the PGM image named "s" on the disk, and put the bitmap into the
345  // image structure I.
346  // I is initialized to the correct size
347  //
348  // exception readPGM may throw various exception if, for example,
349  // the file does not exist, or if the memory cannot be allocated
350  try{
351  vpImageIo::read(I,filename) ;
352  }
353  catch(...)
354  {
355  // an exception is throwned if an exception from readPGM has been catched
356  // here this will result in the end of the program
357  // Note that another error message has been printed from readPGM
358  // to give more information about the error
359  if (opt_ppath.empty()) {
360  std::cerr << std::endl
361  << "ERROR:" << std::endl;
362  std::cerr << " Cannot read " << filename << std::endl;
363  std::cerr << " Check your -i " << ipath << " option, " << std::endl
364  << " or VISP_INPUT_IMAGE_PATH environment variable"
365  << std::endl;
366  }
367  else {
368  std::cerr << std::endl
369  << "ERROR:" << std::endl;
370  std::cerr << " Cannot read " << filename << std::endl;
371  std::cerr << " or your -p " << opt_ppath << " option " <<std::endl
372  << std::endl;
373  }
374  exit(-1);
375 
376  }
377 
378  // We open a window using either the X11 or GTK or GDI window manager
379  // it will be located in 100,100 and titled "tracking using vpDot"
380  // its size is automatically defined by the image (I) size
381 #if defined VISP_HAVE_X11
382  vpDisplayX display;
383 #elif defined VISP_HAVE_GTK
384  vpDisplayGTK display;
385 #elif defined VISP_HAVE_GDI
386  vpDisplayGDI display;
387 #endif
388  if (opt_display) {
389  try{
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  catch(...)
403  {
404  vpERROR_TRACE("Error while displaying the image") ;
405  return(-1) ;
406  }
407  }
408 
409  vpImagePoint cog[4]; // Center of gravity of the dot
410  try{
411  if (opt_display && opt_click_allowed) {
412  // dot coordinates (u,v) = (column,row)
413  std::cout << "Click the four white dots on the object corner clockwise"
414  << std::endl ;
415  for (i=0 ; i < 4 ; i++)
416  {
417  // tracking is initalized if no other parameters are given
418  // to the iniTracking(..) method a right mouse click on the
419  // dot is expected dot location can also be specified
420  // explicitely in the initTracking method :
421  // d.initTracking(I,ip) where ip is the image point from
422  // where the dot need to be searched.
423 
424  d[i].initTracking(I) ;
425  // track the dot and returns its coordinates in the image
426  // results are given in float since many many are usually considered
427  //
428  // an expcetion is thrown by the track method if
429  // - dot is lost
430  // - the number of pixel is too small
431  // - too many pixels are detected (this is usual when a "big" specularity
432  // occurs. The threshold can be modified using the
433  // setMaxDotSize() method
434  d[i].track(I, cog[i]) ;
435  vpDisplay::flush(I) ;
436  }
437  }
438  else{
439  cog[0].set_u( 194 );
440  cog[0].set_v( 88 );
441  d[0].initTracking(I, cog[0] );
442  d[0].track(I, cog[0]);
443  vpDisplay::flush(I) ;
444 
445  cog[1].set_u( 225 );
446  cog[1].set_v( 84 );
447  d[1].initTracking(I, cog[1]);
448  d[1].track(I, cog[1]);
449  vpDisplay::flush(I) ;
450 
451  cog[2].set_u( 242 );
452  cog[2].set_v( 114 );
453  d[2].initTracking(I, cog[2]);
454  d[2].track(I, cog[2]);
455  vpDisplay::flush(I) ;
456 
457  cog[3].set_u( 212 );
458  cog[3].set_v( 131 );
459  d[3].initTracking(I, cog[3]);
460  d[3].track(I, cog[3]);
461  vpDisplay::flush(I) ;
462  }
463  }
464  catch(...)
465  {
466  vpERROR_TRACE("Error in tracking initialization ") ;
467  return(-1) ;
468  }
469 
470  if (opt_display)
471  {
472 
473  // display a red cross (size 10) in the image at the dot center
474  // of gravity location
475  //
476  // WARNING
477  // in the vpDisplay class member's when pixel coordinates
478  // are considered the first element is the row index and the second
479  // is the column index:
480  // vpDisplay::displayCross(Image, row index, column index, size, color)
481  // therefore u and v are inverted wrt to the vpDot specification
482  // Alternatively, to avoid this problem another set of member have
483  // been defined in the vpDisplay class.
484  // If the method name is postfixe with _uv the specification is :
485  // vpDisplay::displayCross_uv(Image, column index, row index, size, color)
486 
487  for (i=0 ; i < 4 ; i++)
488  vpDisplay::displayCross(I, cog[i], 10, vpColor::red) ;
489 
490  // flush the X11 buffer
491  vpDisplay::flush(I) ;
492  }
493 
494  // --------------------------------------------------------
495  // Now wil compute the pose
496  //
497 
498  // The pose will be contained in an homogeneous matrix cMo
499  vpHomogeneousMatrix cMo ;
500 
501 
502  // We need a structure that content both the 3D coordinates of the point
503  // in the object frame and the 2D coordinates of the point expressed in meter
504  // the vpPoint class is ok for that
505  vpPoint P[4] ;
506 
507  // The vpPose class mainly contents a list of vpPoint (that is (X,Y,Z, x, y) )
508  vpPose pose ;
509  // the list of point is cleared (if that's not done before)
510  pose.clearPoint() ;
511 
512  // we set the 3D points coordinates (in meter !) in the object/world frame
513  double L=0.04 ;
514  P[0].setWorldCoordinates(-L,-L, 0 ) ; // (X,Y,Z)
515  P[1].setWorldCoordinates(L,-L, 0 ) ;
516  P[2].setWorldCoordinates(L,L, 0 ) ;
517  P[3].setWorldCoordinates(-L,L, 0 ) ;
518 
519 
520  // set the camera intrinsic parameters
521  // see more details about the model in vpCameraParameters
522  double px = 600 ;
523  double py = 600 ;
524  double u0 = 192 ;
525  double v0 = 144 ;
526  vpCameraParameters cam(px,py,u0,v0) ;
527 
528  // pixel-> meter conversion
529  for (i=0 ; i < 4 ; i++)
530  {
531  // u[i]. v[i] are expressed in pixel
532  // conversion in meter is achieved using
533  // x = (u-u0)/px
534  // y = (v-v0)/py
535  // where px, py, u0, v0 are the intrinsic camera parameters
536  double x=0, y=0;
537  vpPixelMeterConversion::convertPoint(cam, cog[i], x,y) ;
538  P[i].set_x(x) ;
539  P[i].set_y(y) ;
540  }
541 
542 
543  // The pose structure is build, we put in the point list the set of point
544  // here both 2D and 3D world coordinates are known
545  for (i=0 ; i < 4 ; i++)
546  {
547  pose.addPoint(P[i]) ; // and added to the pose computation point list
548  }
549 
550  // compute the initial pose using Dementhon method followed by a non linear
551  // minimisation method
552 
553  // Pose by Lagrange it provides an initialization of the pose
554  pose.computePose(vpPose::LAGRANGE, cMo) ;
555  // the pose is now refined using the virtual visual servoing approach
556  // Warning: cMo needs to be initialized otherwise it may diverge
557  pose.computePose(vpPose::VIRTUAL_VS, cMo) ;
558  if( opt_display ){
559  // display the compute pose
560  pose.display(I,cMo,cam, 0.05, vpColor::red) ;
561  vpDisplay::flush(I) ;
562  }
563 
564  // Covariance Matrix Computation
565  // Uncomment if you want to compute the covariance matrix.
566  // pose.setCovarianceComputation(true); //Important if you want tracker.getCovarianceMatrix() to work.
567 
568  unsigned niter = 0;
569  // this is the loop over the image sequence
570  while (iter < opt_nimages)
571  {
572  try {
573  // set the new image name
574 
575  if (opt_ppath.empty()){
576  s.str("");
577  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
578  filename = dirname + s.str();
579  }
580  else {
581  sprintf( cfilename, opt_ppath.c_str(), iter) ;
582  filename = cfilename ;
583  }
584 
585  // read the image
586  vpImageIo::read(I,filename) ;
587  if (opt_display){
588  // Display the image
589  vpDisplay::display(I) ;
590  //Flush the display
591  vpDisplay::flush(I) ;
592 
593  }
594  // kill the point list
595  pose.clearPoint() ;
596 
597  // track the dot
598  for (i=0 ; i < 4 ; i++)
599  {
600  // track the point
601  d[i].track(I, cog[i]) ;
602  if (opt_display){
603  // display point location
604  vpDisplay::displayCross(I, cog[i], 10,vpColor::red) ;
605  }
606  // pixel->meter conversion
607  {
608  double x=0, y=0;
609  vpPixelMeterConversion::convertPoint(cam, cog[i], x, y) ;
610  P[i].set_x(x) ;
611  P[i].set_y(y) ;
612  }
613 
614  // and added to the pose computation point list
615  pose.addPoint(P[i]) ;
616  }
617  // the pose structure has been updated
618 
619 
620  // the pose is now updated using the virtual visual servoing approach
621  // Dementhon or lagrange is no longuer necessary, pose at the
622  // previous iteration is sufficient
623  pose.computePose(vpPose::VIRTUAL_VS, cMo) ;
624  if (opt_display) {
625  // display the compute pose
626  pose.display(I,cMo,cam, 0.05, vpColor::red) ;
627 
628  vpDisplay::flush(I) ;
629  }
630 
631  // Covariance Matrix Display
632  // Uncomment if you want to print the covariance matrix.
633  // Make sure pose.setCovarianceComputation(true) has been called (uncomment below).
634  // std::cout << pose.getCovarianceMatrix() << std::endl << std::endl;
635 
636  niter++ ;
637  }
638  catch(...){
639  vpERROR_TRACE("Error in tracking loop") ;
640  return(-1) ;
641  }
642  iter += opt_step ;
643  }
644 }
645 #else
646 int
647 main()
648 {
649  vpERROR_TRACE("You do not have X11 or GTK functionalities to display images...");
650 }
651 
652 #endif
653 
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:379
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:133
Define the X11 console to display images.
Definition: vpDisplayX.h:152
void track(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:791
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:1991
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:582
void set_u(const double u)
Definition: vpImagePoint.h:203
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:203
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:214
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:361
This tracker is meant to track a dot (connected pixels with same gray level) on a vpImage...
Definition: vpDot.h:118
void computePose(vpPoseMethodType methode, vpHomogeneousMatrix &cMo)
compute the pose for a given method
Definition: vpPose.cpp:382
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:277
void addPoint(const vpPoint &P)
Add a new point in this array.
Definition: vpPose.cpp:150
void initTracking(const vpImage< unsigned char > &I)
Definition: vpDot.cpp:642
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:128