ViSP
 All Classes Functions Variables Enumerations Enumerator Friends Groups Pages
AROgre.cpp
1 /****************************************************************************
2  *
3  * $Id: AROgre.cpp 4111 2013-02-06 17:27:14Z 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  * Implementation of a simple augmented reality application using the vpAROgre
36  * class.
37  *
38  * Authors:
39  * Bertrand Delabarre
40  *
41  *****************************************************************************/
42 
50 #include <visp/vpConfig.h>
51 #include <iostream>
52 
53 #if defined(VISP_HAVE_OGRE) && defined(VISP_HAVE_DISPLAY)
54 
55 #if defined(VISP_HAVE_X11) && ! defined(APPLE)
56 // produce an error on OSX: ‘typedef int Cursor’
57 // /usr/X11R6/include/X11/X.h:108: error: ‘Cursor’ has a previous
58 // declaration as ‘typedef XID Cursor’. That's why it should not be
59 // used on APPLE platforms
60 # include <visp/vpDisplayX.h>
61 #endif
62 #include <visp/vpDisplayGTK.h>
63 #include <visp/vpDisplayGDI.h>
64 #include <visp/vpDisplayOpenCV.h>
65 #include <visp/vpDisplayD3D.h>
66 #include <visp/vpPose.h>
67 #include <visp/vpPoint.h>
68 #include <visp/vpImagePoint.h>
69 #include <visp/vpDot2.h>
70 #include <visp/vpPixelMeterConversion.h>
71 #include <visp/vpVideoReader.h>
72 #include <visp/vpParseArgv.h>
73 #include <visp/vpIoTools.h>
74 #include <visp/vpDebug.h>
75 #include <visp/vpAROgre.h>
76 
77 // List of allowed command line options
78 #define GETOPTARGS "ci:p:h"
79 
91 void usage(const char *name, const char *badparam, std::string ipath, std::string ppath)
92 {
93  fprintf(stdout, "\n\
94 Test augmented reality using the vpAROgre class.\n\
95 \n\
96 SYNOPSIS\n\
97  %s [-i <test image path>] [-p <personal image path>]\n\
98  [-c] [-h]\n", name);
99 
100  fprintf(stdout, "\n\
101 OPTIONS: Default\n\
102  -i <input image path> %s\n\
103  Set image input path.\n\
104  From this path read images \n\
105  \"ViSP-images/mire-2/image.%%04d.pgm\". These \n\
106  images come from ViSP-images-x.y.z.tar.gz available \n\
107  on the ViSP website.\n\
108  Setting the VISP_INPUT_IMAGE_PATH environment\n\
109  variable produces the same behaviour than using\n\
110  this option.\n\
111  \n\
112  -p <personal image path> %s\n\
113  Specify a personal sequence containing images \n\
114  to process.\n\
115  By image sequence, we mean one file per image.\n\
116  The following image file formats PNM (PGM P5, PPM P6)\n\
117  are supported. The format is selected by analysing \n\
118  the filename extension.\n\
119  Example : \"/Temp/ViSP-images/cube/image.%%04d.pgm\"\n\
120  %%04d is for the image numbering.\n\
121 \n\
122  -c\n\
123  Disable the mouse click. Useful to automaze the \n\
124  execution of this program without humain intervention.\n\
125 \n\
126  -h\n\
127  Print the help.\n",
128  ipath.c_str(), ppath.c_str());
129 
130  if (badparam)
131  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
132 }
146 bool getOptions(int argc, const char **argv, std::string &ipath,
147  std::string &ppath, bool &click_allowed)
148 {
149  const char *optarg;
150  int c;
151  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg)) > 1) {
152 
153  switch (c) {
154  case 'c': click_allowed = false; break;
155  case 'i': ipath = optarg; break;
156  case 'p': ppath = optarg; break;
157  case 'h': usage(argv[0], NULL, ipath, ppath);
158  return false; break;
159 
160  default:
161  usage(argv[0], optarg, ipath, ppath);
162  return false; break;
163  }
164  }
165 
166  if ((c == 1) || (c == -1)) {
167  // standalone param or error
168  usage(argv[0], NULL, ipath, ppath);
169  std::cerr << "ERROR: " << std::endl;
170  std::cerr << " Bad argument " << optarg << std::endl << std::endl;
171  return false;
172  }
173 
174  return true;
175 }
176 
177 
178 #ifndef DOXYGEN_SHOULD_SKIP_THIS
179 
180 class vpAROgreExample : public vpAROgre
181 {
182 public:
183  // The constructor doesn't change here
184  vpAROgreExample(const vpCameraParameters &mcam = vpCameraParameters(),
185  unsigned int width = 640, unsigned int height = 480,
186  const char *resourcePath=NULL)
187  : vpAROgre(mcam, width, height){
188  // Direction vectors
189  if (resourcePath) mResourcePath = resourcePath;
190  std::cout << "mResourcePath: " << mResourcePath<< std::endl;
191  vecDevant = Ogre::Vector3(0,-1,0);
192  }
193 
194 protected :
195 
196  // Attributes
197  // Vector to move
198  Ogre::Vector3 vecDevant;
199  // Animation attribute
200  Ogre::AnimationState * mAnimationState;
201  // The entity representing the robot
202  Ogre::Entity* robot;
203 
204  // Our scene will just be a plane
205  void createScene()
206  {
207  // Lumieres
208  mSceneMgr->setAmbientLight(Ogre::ColourValue((float)0.6,(float)0.6,(float)0.6)); // Default value of lightning
209  Ogre::Light * light = mSceneMgr->createLight();
210  light->setDiffuseColour(1.0,1.0,1.0); // scaled RGB values
211  light->setSpecularColour(1.0,1.0,1.0); // scaled RGB values
212  // Lumiere ponctuelle
213  light->setPosition(-5, -5, 10);
214  light->setType(Ogre::Light::LT_POINT);
215  light->setAttenuation((Ogre::Real)100, (Ogre::Real)1.0, (Ogre::Real)0.045, (Ogre::Real)0.0075);
216  //Ombres
217  light->setCastShadows(true);
218 
219  // Create the Entity
220  robot = mSceneMgr->createEntity("Robot", "robot.mesh");
221  // Attach robot to scene graph
222  Ogre::SceneNode* RobotNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("Robot");
223  RobotNode->attachObject(robot);
224  RobotNode->scale((Ogre::Real)0.001,(Ogre::Real)0.001,(Ogre::Real)0.001);
225  RobotNode->pitch(Ogre::Degree(90));
226  RobotNode->yaw(Ogre::Degree(-90));
227  robot->setCastShadows(true);
228  mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_MODULATIVE);
229 
230  // Add an animation
231  // Set the good animation
232  mAnimationState = robot->getAnimationState( "Idle" );
233  // Start over when finished
234  mAnimationState->setLoop( true );
235  // Animation enabled
236  mAnimationState->setEnabled( true );
237 
238  // Add a ground
239  Ogre::Plane plan;
240  plan.d = 0;
241  plan.normal = Ogre::Vector3::UNIT_Z;
242  Ogre::MeshManager::getSingleton().createPlane("sol",Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plan, (Ogre::Real)0.22, (Ogre::Real)0.16, 10, 10, true, 1, 1, 1);
243  Ogre::Entity* ent = mSceneMgr->createEntity("Entitesol", "sol");
244  Ogre::SceneNode* PlaneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("Entitesol");
245  PlaneNode->attachObject(ent);
246  ent->setMaterialName("Examples/GrassFloor");
247  }
248 
249  bool customframeEnded(const Ogre::FrameEvent& evt) {
250  // Update animation
251  // To move, we add it the time since last frame
252  mAnimationState->addTime( evt.timeSinceLastFrame );
253  return true;
254  }
255 
256 #ifdef VISP_HAVE_OIS
257  bool processInputEvent(const Ogre::FrameEvent& /*evt*/) {
258  mKeyboard->capture();
259  Ogre::Matrix3 rotmy;
260  double angle = -M_PI/8;
261  if(mKeyboard->isKeyDown(OIS::KC_ESCAPE))
262  return false;
263 
264  // Event telling that we will have to move, setting the animation to "walk", if false, annimation goes to "Idle"
265  bool event = false;
266  // Check entries
267  if(mKeyboard->isKeyDown(OIS::KC_Z) || mKeyboard->isKeyDown(OIS::KC_UP)){
268  mSceneMgr->getSceneNode("Robot")->setPosition(mSceneMgr->getSceneNode("Robot")->getPosition()+(Ogre::Real)0.003*vecDevant);
269  event = true;
270  }
271  if(mKeyboard->isKeyDown(OIS::KC_S) || mKeyboard->isKeyDown(OIS::KC_DOWN)){
272  mSceneMgr->getSceneNode("Robot")->setPosition(mSceneMgr->getSceneNode("Robot")->getPosition()-(Ogre::Real)0.003*vecDevant);
273  event = true;
274  }
275  if(mKeyboard->isKeyDown(OIS::KC_Q) || mKeyboard->isKeyDown(OIS::KC_LEFT)){
276  rotmy = Ogre::Matrix3((Ogre::Real)cos(-angle), (Ogre::Real)sin(-angle), 0,
277  (Ogre::Real)(-sin(-angle)), (Ogre::Real)cos(-angle),0,
278  0,0,1);
279  vecDevant=vecDevant*rotmy;
280  mSceneMgr->getSceneNode("Robot")->yaw(Ogre::Radian((Ogre::Real)(-angle)));
281  event = true;
282  }
283  if(mKeyboard->isKeyDown(OIS::KC_D) || mKeyboard->isKeyDown(OIS::KC_RIGHT)){
284  rotmy = Ogre::Matrix3((Ogre::Real)cos(angle), (Ogre::Real)sin(angle), 0,
285  (Ogre::Real)(-sin(angle)), (Ogre::Real)cos(angle),0,
286  0,0,1);
287  vecDevant=vecDevant*rotmy;
288  mSceneMgr->getSceneNode("Robot")->yaw(Ogre::Radian((Ogre::Real)angle));
289  event = true;
290  }
291 
292  // Play the right animation
293  if(event){
294  mAnimationState = robot->getAnimationState("Walk");
295  }
296  else mAnimationState = robot->getAnimationState( "Idle" );
297 
298  // Start over when finished
299  mAnimationState->setLoop( true );
300  // Animation enabled
301  mAnimationState->setEnabled( true );
302 
303  return true;
304  }
305 #endif
306 };
307 
312 void computeInitialPose(vpCameraParameters *mcam, vpImage<unsigned char> &I,
313  vpPose * mPose, vpDot2 *md, vpImagePoint *mcog,
314  vpHomogeneousMatrix *cmo, vpPoint *mP,
315  const bool &opt_click_allowed)
316 {
317  // ---------------------------------------------------
318  // Code inspired from ViSP example of camera pose
319  // ----------------------------------------------------
320  bool opt_display = true;
321 
322 #if defined(VISP_HAVE_X11) && ! defined(APPLE)
323  // produce an error on OSX: ‘typedef int Cursor’
324  // /usr/X11R6/include/X11/X.h:108: error: ‘Cursor’ has a previous
325  // declaration as ‘typedef XID Cursor’. That's why it should not be
326  // used on APPLE platforms
327  vpDisplayX display;
328 #elif defined VISP_HAVE_GTK
329  vpDisplayGTK display;
330 #elif defined VISP_HAVE_GDI
331  vpDisplayGDI display;
332 #elif defined VISP_HAVE_OPENCV
333  vpDisplayOpenCV display;
334 #elif defined VISP_HAVE_D3D9
335  vpDisplayD3D display;
336 #endif
337 
338  for (unsigned int i=0 ; i < 4 ; i++)
339  {
340  if (opt_display) {
341  md[i].setGraphics(true) ;
342  }
343  else {
344  md[i].setGraphics(false) ;
345  }
346  }
347 
348  if (opt_display) {
349  try{
350  // Display size is automatically defined by the image (I) size
351  display.init(I,100,100,"Preliminary Pose Calculation");
352  // display the image
353  // The image class has a member that specify a pointer toward
354  // the display that has been initialized in the display declaration
355  // therefore is is no longuer necessary to make a reference to the
356  // display variable.
357  vpDisplay::display(I) ;
358  //Flush the display
359  vpDisplay::flush(I) ;
360 
361  }
362  catch(...)
363  {
364  vpERROR_TRACE("Error while displaying the image") ;
365  return ;
366  }
367  }
368 
369  std::cout<<"************************************************************************************"<<std::endl;
370  std::cout<<"*************************** Preliminary Pose Calculation ***************************"<<std::endl;
371  std::cout<<"****************************** Click on the 4 dots *******************************"<<std::endl;
372  std::cout<<"********Dot1 : (-x,-y,0), Dot2 : (x,-y,0), Dot3 : (x,y,0), Dot4 : (-x,y,0)**********"<<std::endl;
373  std::cout<<"************************************************************************************"<<std::endl;
374 
375  try{
376  vpImagePoint ip[4];
377  if (! opt_click_allowed) {
378  ip[0].set_i( 265 );
379  ip[0].set_j( 93 );
380  ip[1].set_i( 248 );
381  ip[1].set_j( 242 );
382  ip[2].set_i( 166 );
383  ip[2].set_j( 215 );
384  ip[3].set_i( 178 );
385  ip[3].set_j( 85 );
386  }
387  for(unsigned int i=0;i<4;i++) {
388  // by using setGraphics, we request to see the edges of the dot
389  // in red on the screen.
390  // It uses the overlay image plane.
391  // The default of this setting is that it is time consumming
392 
393  md[i].setGraphics(true) ;
394  md[i].setGrayLevelPrecision(0.7);
395  md[i].setSizePrecision(0.5);
396 
397  for(unsigned int j = 0;j<i;j++)
398  md[j].display(I) ;
399 
400  // flush the display buffer
401  vpDisplay::flush(I);
402  try{
403  if (opt_click_allowed)
404  md[i].initTracking(I);
405  else
406  md[i].initTracking(I, ip[i]);
407  }
408  catch(...){
409  }
410 
411  mcog[i] = md[i].getCog();
412  // an expcetion is thrown by the track method if
413  // - dot is lost
414  // - the number of pixel is too small
415  // - too many pixels are detected (this is usual when a "big" specularity
416  // occurs. The threshold can be modified using the
417  // setNbMaxPoint(int) method
418  if (opt_display) {
419  md[i].display(I) ;
420  // flush the display buffer
421  vpDisplay::flush(I) ;
422  }
423  }
424  }
425  catch(vpException e){
426  vpERROR_TRACE("Error while tracking dots") ;
427  vpCTRACE << e;
428  return;
429  }
430 
431  if (opt_display)
432  {
433  // display a red cross (size 10) in the image at the dot center
434  // of gravity location
435  //
436  // WARNING
437  // in the vpDisplay class member's when pixel coordinates
438  // are considered the first element is the row index and the second
439  // is the column index:
440  // vpDisplay::displayCross(Image, row index, column index, size, color)
441  // therefore u and v are inverted wrt to the vpDot specification
442  // Alternatively, to avoid this problem another set of member have
443  // been defined in the vpDisplay class.
444  // If the method name is postfixe with _uv the specification is :
445  // vpDisplay::displayCross_uv(Image, column index, row index, size, color)
446 
447  for (unsigned int i=0 ; i < 4 ; i++)
448  vpDisplay::displayCross(I, mcog[i], 10, vpColor::red) ;
449 
450  // flush the X11 buffer
451  vpDisplay::flush(I) ;
452  }
453 
454  // --------------------------------------------------------
455  // Now we will compute the pose
456  // --------------------------------------------------------
457 
458  // the list of point is cleared (if that's not done before)
459  mPose->clearPoint() ;
460 
461  // we set the 3D points coordinates (in meter !) in the object/world frame
462  double l=0.06 ;
463  double L=0.07 ;
464  mP[0].setWorldCoordinates(-L,-l, 0 ) ; // (X,Y,Z)
465  mP[1].setWorldCoordinates(L,-l, 0 ) ;
466  mP[2].setWorldCoordinates(L,l, 0 ) ;
467  mP[3].setWorldCoordinates(-L,l, 0 ) ;
468 
469  // pixel-> meter conversion
470  for (unsigned int i=0 ; i < 4 ; i++)
471  {
472  // u[i]. v[i] are expressed in pixel
473  // conversion in meter is achieved using
474  // x = (u-u0)/px
475  // y = (v-v0)/py
476  // where px, py, u0, v0 are the intrinsic camera parameters
477  double x=0, y=0;
478  vpPixelMeterConversion::convertPoint(*mcam, mcog[i], x,y) ;
479  mP[i].set_x(x) ;
480  mP[i].set_y(y) ;
481  }
482 
483 
484  // The pose structure is build, we put in the point list the set of point
485  // here both 2D and 3D world coordinates are known
486  for (unsigned int i=0 ; i < 4 ; i++)
487  {
488  mPose->addPoint(mP[i]) ; // and added to the pose computation point list
489  }
490 
491  // compute the initial pose using Dementhon method followed by a non linear
492  // minimisation method
493 
494  // Pose by Lagrange it provides an initialization of the pose
495  mPose->computePose(vpPose::LAGRANGE, *cmo) ;
496  // the pose is now refined using the virtual visual servoing approach
497  // Warning: cMo needs to be initialized otherwise it may diverge
498  mPose->computePose(vpPose::VIRTUAL_VS, *cmo) ;
499 
500  // Display breifly just to have a glimpse a the ViSP pose
501  // while(cpt<500){
502  if( opt_display ){
503  // Display the computed pose
504  mPose->display(I,*cmo,*mcam, 0.05, vpColor::red) ;
505  vpDisplay::flush(I) ;
506  vpTime::wait(800);
507  }
508 }
509 
510 #endif
511 
512 int main(int argc, const char **argv)
513 {
514  std::string env_ipath;
515  std::string opt_ipath;
516  std::string ipath;
517  std::string opt_ppath;
518  std::string dirname;
519  std::string filename;
520  bool opt_click_allowed = true;
521 
522  // Get the VISP_IMAGE_PATH environment variable value
523  char *ptenv = getenv("VISP_INPUT_IMAGE_PATH");
524  if (ptenv != NULL)
525  env_ipath = ptenv;
526 
527  // Set the default input path
528  if (! env_ipath.empty())
529  ipath = env_ipath;
530 
531 
532  // Read the command line options
533  if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_click_allowed) == false) {
534  exit (-1);
535  }
536 
537  // Get the option values
538  if (!opt_ipath.empty())
539  ipath = opt_ipath;
540 
541  // Compare ipath and env_ipath. If they differ, we take into account
542  // the input path comming from the command line option
543  if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
544  if (ipath != env_ipath) {
545  std::cout << std::endl
546  << "WARNING: " << std::endl;
547  std::cout << " Since -i <visp image path=" << ipath << "> "
548  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
549  << " we skip the environment variable." << std::endl;
550  }
551  }
552 
553  // Test if an input path is set
554  if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty() ){
555  usage(argv[0], NULL, ipath, opt_ppath);
556  std::cerr << std::endl
557  << "ERROR:" << std::endl;
558  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
559  << std::endl
560  << " environment variable to specify the location of the " << std::endl
561  << " image path where test images are located." << std::endl
562  << " Use -p <personal image path> option if you want to "<<std::endl
563  << " use personal images." << std::endl
564  << std::endl;
565 
566  exit(-1);
567  }
568 
569  std::ostringstream s;
570 
571  if (opt_ppath.empty()){
572  // Set the path location of the image sequence
573  dirname = ipath + vpIoTools::path("/ViSP-images/mire-2/");
574 
575  // Build the name of the image file
576 
577  s.setf(std::ios::right, std::ios::adjustfield);
578  s << "image.%04d.pgm";
579  filename = dirname + s.str();
580  }
581  else {
582  filename = opt_ppath;
583  }
584 
585  //We will read a sequence of images
586  vpVideoReader grabber;
587  grabber.setFirstFrameIndex(1);
588  grabber.setFileName(filename.c_str());
589  // Grey level image associated to a display in the initial pose computation
590  vpImage<unsigned char> Idisplay;
591  // Grey level image to track points
593  // RGBa image to get background
594  vpImage<vpRGBa> IC;
595  // Matrix representing camera parameters
597 
598  // Variables used for pose computation purposes
599  vpPose mPose;
600  vpDot2 md[4];
601  vpImagePoint mcog[4];
602  vpPoint mP[4];
603 
604  // CameraParameters we got from calibration
605  // Keep u0 and v0 as center of the screen
606  vpCameraParameters mcam;
607 
608  // Read the PGM image named "filename" on the disk, and put the
609  // bitmap into the image structure I. I is initialized to the
610  // correct size
611  //
612  // exception readPGM may throw various exception if, for example,
613  // the file does not exist, or if the memory cannot be allocated
614  try{
615  vpCTRACE << "Load: " << filename << std::endl;
616  grabber.open(Idisplay);
617  grabber.acquire(Idisplay);
618  vpCameraParameters mcamTmp(592,570,grabber.getWidth()/2,grabber.getHeight()/2);
619  // Compute the initial pose of the camera
620  computeInitialPose(&mcamTmp, Idisplay, &mPose, md, mcog, &cmo, mP,
621  opt_click_allowed);
622  // Close the framegrabber
623  grabber.close();
624 
625  // Associate the grabber to the RGBa image
626  grabber.open(IC);
627  mcam.init(mcamTmp);
628  }
629  catch(...)
630  {
631  // an exception is thrown if an exception from readPGM has been caught
632  // here this will result in the end of the program
633  // Note that another error message has been printed from readPGM
634  // to give more information about the error
635  std::cerr << std::endl
636  << "ERROR:" << std::endl;
637  std::cerr << " Cannot read " << filename << std::endl;
638  std::cerr << " Check your -i " << ipath << " option " << std::endl
639  << " or VISP_INPUT_IMAGE_PATH environment variable."
640  << std::endl;
641  exit(-1);
642  }
643 
644  // Create a vpRAOgre object with color background
645  vpAROgreExample ogre(mcam, (unsigned int)grabber.getWidth(), (unsigned int)grabber.getHeight());
646  // Initialize it
647  ogre.init(IC);
648 
649  try
650  {
651  // Rendering loop
652  while(ogre.continueRendering()){
653  // Acquire a frame
654  grabber.acquire(IC);
655 
656  // Convert it to a grey level image for tracking purpose
658 
659  // Update pose calculation
660  try{
661  // kill the point list
662  mPose.clearPoint() ;
663 
664  // track the dot
665  for (int i=0 ; i < 4 ; i++)
666  {
667  // track the point
668  md[i].track(I, mcog[i]) ;
669  md[i].setGrayLevelPrecision(0.90);
670  // pixel->meter conversion
671  {
672  double x=0, y=0;
673  vpPixelMeterConversion::convertPoint(mcam, mcog[i], x, y) ;
674  mP[i].set_x(x) ;
675  mP[i].set_y(y) ;
676  }
677 
678  // and added to the pose computation point list
679  mPose.addPoint(mP[i]) ;
680  }
681  // the pose structure has been updated
682 
683  // the pose is now updated using the virtual visual servoing approach
684  // Dementhon or lagrange is no longuer necessary, pose at the
685  // previous iteration is sufficient
686  mPose.computePose(vpPose::VIRTUAL_VS, cmo);
687  }
688  catch(...){
689  vpERROR_TRACE("Error in tracking loop") ;
690  return false;
691  }
692 
693  // Display with ogre
694  ogre.display(IC,cmo);
695 
696  // Wait so that the video does not go too fast
697  vpTime::wait(15);
698  }
699  // Close the grabber
700  grabber.close();
701  }
702  catch (Ogre::Exception& e)
703  {
704  std::cerr << "Exception:\n";
705  std::cerr << e.getFullDescription().c_str() << "\n";
706  return 1;
707  }
708  catch (...)
709  {
710  std::cerr << "Exception: " << "\n";
711  return 1;
712  }
713 
714  return EXIT_SUCCESS;
715 }
716 #else // VISP_HAVE_OGRE && VISP_HAVE_DISPLAY
717 int
718 main()
719 {
720  std::cout << "You should install Ogre3D to run this example..." << std::endl;
721 }
722 #endif