Visual Servoing Platform  version 3.0.0
photometricVisualServoing.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  * Authors:
31  * Eric Marchand
32  * Christophe Collewet
33  *
34  *****************************************************************************/
35 
43 #include <visp3/core/vpDebug.h>
44 
45 #include <visp3/core/vpImage.h>
46 #include <visp3/io/vpImageIo.h>
47 #include <visp3/core/vpImageTools.h>
48 
49 #include <visp3/core/vpCameraParameters.h>
50 #include <visp3/core/vpTime.h>
51 #include <visp3/robot/vpSimulatorCamera.h>
52 
53 #include <visp3/core/vpMath.h>
54 #include <visp3/core/vpHomogeneousMatrix.h>
55 #include <visp3/gui/vpDisplayGTK.h>
56 #include <visp3/gui/vpDisplayGDI.h>
57 #include <visp3/gui/vpDisplayOpenCV.h>
58 #include <visp3/gui/vpDisplayD3D.h>
59 #include <visp3/gui/vpDisplayX.h>
60 
61 #include <visp3/visual_features/vpFeatureLuminance.h>
62 #include <visp3/io/vpParseArgv.h>
63 
64 #include <visp3/robot/vpImageSimulator.h>
65 #include <stdlib.h>
66 #define Z 1
67 
68 #include <visp3/io/vpParseArgv.h>
69 #include <visp3/core/vpIoTools.h>
70 
71 // List of allowed command line options
72 #define GETOPTARGS "cdi:n:h"
73 
74 void usage(const char *name, const char *badparam, std::string ipath, int niter);
75 bool getOptions(int argc, const char **argv, std::string &ipath,
76  bool &click_allowed, bool &display, int &niter);
77 
88 void usage(const char *name, const char *badparam, std::string ipath, int niter)
89 {
90  fprintf(stdout, "\n\
91 Tracking of Surf key-points.\n\
92 \n\
93 SYNOPSIS\n\
94  %s [-i <input image path>] [-c] [-d] [-n <number of iterations>] [-h]\n", name);
95 
96  fprintf(stdout, "\n\
97 OPTIONS: Default\n\
98  -i <input image path> %s\n\
99  Set image input path.\n\
100  From this path read \"ViSP-images/doisneau/doisneau.jpg\"\n\
101  images. \n\
102  Setting the VISP_INPUT_IMAGE_PATH environment\n\
103  variable produces the same behaviour than using\n\
104  this option.\n\
105 \n\
106  -c\n\
107  Disable the mouse click. Useful to automaze the \n\
108  execution of this program without humain intervention.\n\
109 \n\
110  -d \n\
111  Turn off the display.\n\
112 \n\
113  -n %%d %d\n\
114  Number of iterations.\n\
115 \n\
116  -h\n\
117  Print the help.\n",
118  ipath.c_str(), niter);
119 
120  if (badparam)
121  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
122 }
137 bool getOptions(int argc, const char **argv, std::string &ipath,
138  bool &click_allowed, bool &display, int &niter)
139 {
140  const char *optarg_;
141  int c;
142  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
143 
144  switch (c) {
145  case 'c': click_allowed = false; break;
146  case 'd': display = false; break;
147  case 'i': ipath = optarg_; break;
148  case 'n': niter = atoi(optarg_); break;
149  case 'h': usage(argv[0], NULL, ipath, niter); return false; break;
150 
151  default:
152  usage(argv[0], optarg_, ipath, niter);
153  return false; break;
154  }
155  }
156 
157  if ((c == 1) || (c == -1)) {
158  // standalone param or error
159  usage(argv[0], NULL, ipath, niter);
160  std::cerr << "ERROR: " << std::endl;
161  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
162  return false;
163  }
164 
165  return true;
166 }
167 
168 
169 
170 int
171 main(int argc, const char ** argv)
172 {
173  try {
174  std::string env_ipath;
175  std::string opt_ipath;
176  std::string ipath;
177  std::string filename;
178  bool opt_click_allowed = true;
179  bool opt_display = true;
180  int opt_niter = 400;
181 
182  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
183  env_ipath = vpIoTools::getViSPImagesDataPath();
184 
185  // Set the default input path
186  if (! env_ipath.empty())
187  ipath = env_ipath;
188 
189  // Read the command line options
190  if (getOptions(argc, argv, opt_ipath, opt_click_allowed,
191  opt_display, opt_niter) == false) {
192  return (-1);
193  }
194 
195  // Get the option values
196  if (!opt_ipath.empty())
197  ipath = opt_ipath;
198 
199  // Compare ipath and env_ipath. If they differ, we take into account
200  // the input path comming from the command line option
201  if (!opt_ipath.empty() && !env_ipath.empty()) {
202  if (ipath != env_ipath) {
203  std::cout << std::endl
204  << "WARNING: " << std::endl;
205  std::cout << " Since -i <visp image path=" << ipath << "> "
206  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
207  << " we skip the environment variable." << std::endl;
208  }
209  }
210 
211  // Test if an input path is set
212  if (opt_ipath.empty() && env_ipath.empty()){
213  usage(argv[0], NULL, ipath, opt_niter);
214  std::cerr << std::endl
215  << "ERROR:" << std::endl;
216  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
217  << std::endl
218  << " environment variable to specify the location of the " << std::endl
219  << " image path where test images are located." << std::endl << std::endl;
220  exit(-1);
221  }
222 
223  vpImage<unsigned char> Itexture ;
224  filename = vpIoTools::createFilePath(ipath, "ViSP-images/Klimt/Klimt.pgm");
225  vpImageIo::read(Itexture,filename) ;
226 
227  vpColVector X[4];
228  for (int i = 0; i < 4; i++) X[i].resize(3);
229  // Top left corner
230  X[0][0] = -0.3;
231  X[0][1] = -0.215;
232  X[0][2] = 0;
233 
234  // Top right corner
235  X[1][0] = 0.3;
236  X[1][1] = -0.215;
237  X[1][2] = 0;
238 
239  // Bottom right corner
240  X[2][0] = 0.3;
241  X[2][1] = 0.215;
242  X[2][2] = 0;
243 
244  //Bottom left corner
245  X[3][0] = -0.3;
246  X[3][1] = 0.215;
247  X[3][2] = 0;
248 
249  vpImageSimulator sim;
250 
252  sim.init(Itexture, X);
253 
254  vpCameraParameters cam(870, 870, 160, 120);
255 
256  // ----------------------------------------------------------
257  // Create the framegraber (here a simulated image)
258  vpImage<unsigned char> I(240,320,0) ;
260 
261  //camera desired position
262  vpHomogeneousMatrix cdMo ;
263  cdMo[2][3] = 1 ;
264 
265  //set the robot at the desired position
266  sim.setCameraPosition(cdMo) ;
267  sim.getImage(I,cam); // and aquire the image Id
268  Id = I ;
269 
270  // display the image
271 #if defined VISP_HAVE_X11
272  vpDisplayX d;
273 #elif defined VISP_HAVE_GDI
274  vpDisplayGDI d;
275 #elif defined VISP_HAVE_GTK
276  vpDisplayGTK d;
277 #elif defined VISP_HAVE_OPENCV
278  vpDisplayOpenCV d;
279 #endif
280 
281 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_OPENCV)
282  if (opt_display) {
283  d.init(I, 20, 10, "Photometric visual servoing : s") ;
285  vpDisplay::flush(I);
286  }
287  if (opt_display && opt_click_allowed) {
288  std::cout << "Click in the image to continue..." << std::endl;
290  }
291 #endif
292 
293  // ----------------------------------------------------------
294  // position the robot at the initial position
295  // ----------------------------------------------------------
296 
297  //camera desired position
298  vpHomogeneousMatrix cMo ;
299  cMo.buildFrom(0,0,1.2,vpMath::rad(15),vpMath::rad(-5),vpMath::rad(20));
300  vpHomogeneousMatrix wMo; // Set to identity
301  vpHomogeneousMatrix wMc; // Camera position in the world frame
302 
303  //set the robot at the desired position
304  sim.setCameraPosition(cMo) ;
305  I =0 ;
306  sim.getImage(I,cam); // and aquire the image Id
307 
308 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK)
309  if (opt_display) {
310  vpDisplay::display(I) ;
311  vpDisplay::flush(I) ;
312  }
313  if (opt_display && opt_click_allowed) {
314  std::cout << "Click in the image to continue..." << std::endl;
316  }
317 #endif
318 
319  vpImage<unsigned char> Idiff ;
320  Idiff = I ;
321 
322  vpImageTools::imageDifference(I,Id,Idiff) ;
323 
324  // Affiche de l'image de difference
325 #if defined VISP_HAVE_X11
326  vpDisplayX d1;
327 #elif defined VISP_HAVE_GDI
328  vpDisplayGDI d1;
329 #elif defined VISP_HAVE_GTK
330  vpDisplayGTK d1;
331 #endif
332 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK)
333  if (opt_display) {
334  d1.init(Idiff, 40+(int)I.getWidth(), 10, "photometric visual servoing : s-s* ") ;
335  vpDisplay::display(Idiff) ;
336  vpDisplay::flush(Idiff) ;
337  }
338 #endif
339  // create the robot (here a simulated free flying camera)
340  vpSimulatorCamera robot;
341  robot.setSamplingTime(0.04);
342  wMc = wMo * cMo.inverse();
343  robot.setPosition(wMc);
344 
345  // ------------------------------------------------------
346  // Visual feature, interaction matrix, error
347  // s, Ls, Lsd, Lt, Lp, etc
348  // ------------------------------------------------------
349 
350  // current visual feature built from the image
351  // (actually, this is the image...)
352  vpFeatureLuminance sI ;
353  sI.init( I.getHeight(), I.getWidth(), Z) ;
354  sI.setCameraParameters(cam) ;
355  sI.buildFrom(I) ;
356 
357  // desired visual feature built from the image
358  vpFeatureLuminance sId ;
359  sId.init(I.getHeight(), I.getWidth(), Z) ;
360  sId.setCameraParameters(cam) ;
361  sId.buildFrom(Id) ;
362 
363  // Matrice d'interaction, Hessien, erreur,...
364  vpMatrix Lsd; // matrice d'interaction a la position desiree
365  vpMatrix Hsd; // hessien a la position desiree
366  vpMatrix H ; // Hessien utilise pour le levenberg-Marquartd
367  vpColVector error ; // Erreur I-I*
368 
369  // Compute the interaction matrix
370  // link the variation of image intensity to camera motion
371 
372  // here it is computed at the desired position
373  sId.interaction(Lsd) ;
374 
375  // Compute the Hessian H = L^TL
376  Hsd = Lsd.AtA() ;
377 
378  // Compute the Hessian diagonal for the Levenberg-Marquartd
379  // optimization process
380  unsigned int n = 6 ;
381  vpMatrix diagHsd(n,n) ;
382  diagHsd.eye(n);
383  for(unsigned int i = 0 ; i < n ; i++) diagHsd[i][i] = Hsd[i][i];
384 
385  // ------------------------------------------------------
386  // Control law
387  double lambda ; //gain
388  vpColVector e ;
389  vpColVector v ; // camera velocity send to the robot
390 
391  // ----------------------------------------------------------
392  // Minimisation
393 
394  double mu ; // mu = 0 : Gauss Newton ; mu != 0 : LM
395  double lambdaGN;
396 
397  mu = 0.01;
398  lambda = 30 ;
399  lambdaGN = 30;
400 
401  // set a velocity control mode
403 
404  // ----------------------------------------------------------
405  int iter = 1;
406  int iterGN = 90 ; // swicth to Gauss Newton after iterGN iterations
407 
408  double normeError = 0;
409  do {
410  std::cout << "--------------------------------------------" << iter++ << std::endl ;
411 
412  // Acquire the new image
413  sim.setCameraPosition(cMo) ;
414  sim.getImage(I,cam) ;
415 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK)
416  if (opt_display) {
417  vpDisplay::display(I) ;
418  vpDisplay::flush(I) ;
419  }
420 #endif
421  vpImageTools::imageDifference(I,Id,Idiff) ;
422 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK)
423  if (opt_display) {
424  vpDisplay::display(Idiff) ;
425  vpDisplay::flush(Idiff) ;
426  }
427 #endif
428  // Compute current visual feature
429  sI.buildFrom(I) ;
430 
431  // compute current error
432  sI.error(sId,error) ;
433 
434  normeError = (error.sumSquare());
435  std::cout << "|e| "<<normeError <<std::endl ;
436 
437  // double t = vpTime::measureTimeMs() ;
438 
439  // ---------- Levenberg Marquardt method --------------
440  {
441  if (iter > iterGN)
442  {
443  mu = 0.0001 ;
444  lambda = lambdaGN;
445  }
446 
447  // Compute the levenberg Marquartd term
448  {
449  H = ((mu * diagHsd) + Hsd).inverseByLU();
450  }
451  // compute the control law
452  e = H * Lsd.t() *error ;
453 
454  v = - lambda*e;
455  }
456 
457  std::cout << "lambda = " << lambda << " mu = " << mu ;
458  std::cout << " |Tc| = " << sqrt(v.sumSquare()) << std::endl;
459 
460  // send the robot velocity
462  wMc = robot.getPosition();
463  cMo = wMc.inverse() * wMo;
464  }
465  while(normeError > 10000 && iter < opt_niter);
466 
467  v = 0 ;
469 
470  return 0;
471  }
472  catch(vpException e) {
473  std::cout << "Catch an exception: " << e << std::endl;
474  return 1;
475  }
476 }
void setPosition(const vpHomogeneousMatrix &wMc)
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:92
void init(const vpImage< unsigned char > &I, vpColVector *X)
void setVelocity(const vpRobot::vpControlFrameType frame, const vpColVector &vel)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1091
unsigned int getWidth() const
Definition: vpImage.h:161
Implementation of an homogeneous matrix and operations on such kind of matrices.
Class that defines the simplest robot: a free flying camera.
void buildFrom(vpImage< unsigned char > &I)
void getImage(vpImage< unsigned char > &I, const vpCameraParameters &cam)
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
void setCameraParameters(vpCameraParameters &_cam)
Define the X11 console to display images.
Definition: vpDisplayX.h:148
error that can be emited by ViSP classes.
Definition: vpException.h:73
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
static void imageDifference(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Idiff)
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
virtual vpRobotStateType setRobotState(const vpRobot::vpRobotStateType newState)
Definition: vpRobot.cpp:201
virtual void setSamplingTime(const double &delta_t)
void setCameraPosition(const vpHomogeneousMatrix &cMt)
Initialize the velocity controller.
Definition: vpRobot.h:68
void setInterpolationType(const vpInterpolationType interplt)
vpMatrix AtA() const
Definition: vpMatrix.cpp:391
Class that defines the image luminance visual feature.
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1265
vpMatrix interaction(const unsigned int select=FEATURE_ALL)
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:206
The vpDisplayOpenCV allows to display image using the opencv library.
Generic class defining intrinsic camera parameters.
vpColVector error(const vpBasicFeature &s_star, const unsigned int select=FEATURE_ALL)
Class which enables to project an image in the 3D space and get the view of a virtual camera...
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:141
vpHomogeneousMatrix getPosition() const
void buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
static double rad(double deg)
Definition: vpMath.h:104
double sumSquare() const
vpMatrix t() const
Definition: vpMatrix.cpp:221
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
vpMatrix inverseByLU() const
vpHomogeneousMatrix inverse() const
unsigned int getHeight() const
Definition: vpImage.h:152
virtual bool getClick(bool blocking=true)=0
static void read(vpImage< unsigned char > &I, const char *filename)
Definition: vpImageIo.cpp:274