Visual Servoing Platform  version 3.0.1
keyPointSurf.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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  * Description:
31  * Tracking of Surf key points.
32  *
33  * Authors:
34  * Nicolas Melchior
35  * Fabien Spindler
36  *
37  *****************************************************************************/
52 #include <visp3/core/vpDebug.h>
53 #include <visp3/core/vpConfig.h>
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <sstream>
57 #include <iomanip>
58 #if ((defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) && defined(VISP_HAVE_OPENCV_NONFREE) && (VISP_HAVE_OPENCV_VERSION < 0x030000))
59 
60 #include <visp3/vision/vpKeyPointSurf.h>
61 
62 #include <visp3/core/vpImage.h>
63 #include <visp3/io/vpImageIo.h>
64 #include <visp3/core/vpImagePoint.h>
65 #include <visp3/gui/vpDisplayX.h>
66 #include <visp3/gui/vpDisplayGTK.h>
67 #include <visp3/gui/vpDisplayGDI.h>
68 
69 #include <visp3/io/vpParseArgv.h>
70 #include <visp3/core/vpIoTools.h>
71 
72 // List of allowed command line options
73 #define GETOPTARGS "cdi:h"
74 
75 void usage(const char *name, const char *badparam, std::string ipath);
76 bool getOptions(int argc, const char **argv, std::string &ipath, bool &click_allowed, bool &display);
77 
87 void usage(const char *name, const char *badparam, std::string ipath)
88 {
89  fprintf(stdout, "\n\
90 Tracking of Surf key-points.\n\
91 \n\
92 SYNOPSIS\n\
93  %s [-i <input image path>] [-c] [-d] [-h]\n", name);
94 
95  fprintf(stdout, "\n\
96 OPTIONS: Default\n\
97  -i <input image path> %s\n\
98  Set image input path.\n\
99  From this path read \"ViSP-images/line/image.%%04d.pgm\"\n\
100  images. \n\
101  Setting the VISP_INPUT_IMAGE_PATH environment\n\
102  variable produces the same behaviour than using\n\
103  this option.\n\
104 \n\
105  -c\n\
106  Disable the mouse click. Useful to automaze the \n\
107  execution of this program without humain intervention.\n\
108 \n\
109  -d \n\
110  Turn off the display.\n\
111 \n\
112  -h\n\
113  Print the help.\n",
114  ipath.c_str());
115 
116  if (badparam)
117  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
118 }
132 bool getOptions(int argc, const char **argv, std::string &ipath, bool &click_allowed, bool &display)
133 {
134  const char *optarg_;
135  int c;
136  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
137 
138  switch (c) {
139  case 'c': click_allowed = false; break;
140  case 'd': display = false; break;
141  case 'i': ipath = optarg_; break;
142  case 'h': usage(argv[0], NULL, ipath); return false; break;
143 
144  default:
145  usage(argv[0], optarg_, ipath);
146  return false; break;
147  }
148  }
149 
150  if ((c == 1) || (c == -1)) {
151  // standalone param or error
152  usage(argv[0], NULL, ipath);
153  std::cerr << "ERROR: " << std::endl;
154  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
155  return false;
156  }
157 
158  return true;
159 }
160 
161 
162 int
163 main(int argc, const char ** argv)
164 {
165  try {
166  std::string env_ipath;
167  std::string opt_ipath;
168  std::string ipath;
169  std::string dirname;
170  std::string filename;
171  bool opt_click_allowed = true;
172  bool opt_display = true;
173 
174  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
175  env_ipath = vpIoTools::getViSPImagesDataPath();
176 
177  // Set the default input path
178  if (! env_ipath.empty())
179  ipath = env_ipath;
180 
181  // Read the command line options
182  if (getOptions(argc, argv, opt_ipath, opt_click_allowed,
183  opt_display) == false) {
184  exit (-1);
185  }
186 
187  // Get the option values
188  if (!opt_ipath.empty())
189  ipath = opt_ipath;
190 
191  // Compare ipath and env_ipath. If they differ, we take into account
192  // the input path comming from the command line option
193  if (!opt_ipath.empty() && !env_ipath.empty()) {
194  if (ipath != env_ipath) {
195  std::cout << std::endl
196  << "WARNING: " << std::endl;
197  std::cout << " Since -i <visp image path=" << ipath << "> "
198  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
199  << " we skip the environment variable." << std::endl;
200  }
201  }
202 
203  // Test if an input path is set
204  if (opt_ipath.empty() && env_ipath.empty()){
205  usage(argv[0], NULL, ipath);
206  std::cerr << std::endl
207  << "ERROR:" << std::endl;
208  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
209  << std::endl
210  << " environment variable to specify the location of the " << std::endl
211  << " image path where test images are located." << std::endl << std::endl;
212  exit(-1);
213  }
214 
215  // Declare an image, this is a gray level image (unsigned char)
216  // it size is not defined yet, it will be defined when the image will
217  // read on the disk
220 
221  // Set the path location of the image sequence
222  dirname = vpIoTools::createFilePath(ipath, "ViSP-images/cube");
223 
224  // Build the name of the image file
225  unsigned int iter = 0; // Image number
226  std::ostringstream s;
227  s.setf(std::ios::right, std::ios::adjustfield);
228  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
229  filename = vpIoTools::createFilePath(dirname, s.str());
230 
231  // Read the PGM image named "filename" on the disk, and put the
232  // bitmap into the image structure I. I is initialized to the
233  // correct size
234  //
235  // exception readPGM may throw various exception if, for example,
236  // the file does not exist, or if the memory cannot be allocated
237  try{
238  vpCTRACE << "Load: " << filename << std::endl;
239 
240  vpImageIo::read(Iref, filename) ;
241  }
242  catch(...)
243  {
244  // an exception is throwned if an exception from readPGM has been catched
245  // here this will result in the end of the program
246  // Note that another error message has been printed from readPGM
247  // to give more information about the error
248  std::cerr << std::endl
249  << "ERROR:" << std::endl;
250  std::cerr << " Cannot read " << filename << std::endl;
251  std::cerr << " Check your -i " << ipath << " option " << std::endl
252  << " or VISP_INPUT_IMAGE_PATH environment variable."
253  << std::endl;
254  exit(-1);
255  }
256 
257  // We open a window using either X11, GTK or GDI.
258 #if defined VISP_HAVE_X11
259  vpDisplayX display[2];
260 #elif defined VISP_HAVE_GTK
261  vpDisplayGTK display[2];
262 #elif defined VISP_HAVE_GDI
263  vpDisplayGDI display[2];
264 #endif
265 
266  if (opt_display) {
267  try{
268  // Display size is automatically defined by the image (I) size
269  display[0].init(Iref, 100, 100,"Display reference image") ;
270  vpDisplay::display(Iref) ;
271  vpDisplay::flush(Iref) ;
272  }
273  catch(...)
274  {
275  vpERROR_TRACE("Error while displaying the image") ;
276  exit(-1);
277  }
278  }
279 
280  vpImagePoint corners[2];
281  if (opt_display && opt_click_allowed)
282  {
283  std::cout << "Click on the top left and the bottom right corners to define the part of the image where the reference points will be computed" << std::endl;
284  for (unsigned int i=0 ; i < 2 ; i++)
285  {
286  vpDisplay::getClick(Iref, corners[i]);
287  std::cout << corners[i] << std::endl;
288  }
289  }
290  else
291  {
292  corners[0].set_ij(156,209);
293  corners[1].set_ij(272,378);
294  }
295 
296  if (opt_display)
297  {
298  //Display the rectangle which defines the part of the image where the reference points are computed.
299  vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::green);
300  vpDisplay::flush(Iref);
301  }
302 
303  if (opt_click_allowed)
304  {
305  std::cout << "Click on the image to continue" << std::endl;
306  vpDisplay::getClick(Iref);
307  }
308 
309  vpKeyPointSurf surf;
310  // unsigned int nbrRef;
311  unsigned int height, width;
312  height = (unsigned int)(corners[1].get_i() - corners[0].get_i());
313  width = (unsigned int)(corners[1].get_j() - corners[0].get_j());
314 
315  //Computes the reference points
316  /* nbrRef = */ surf.buildReference(Iref, corners[0], height, width);
317 
318  unsigned int nbrPair = 0;
319 
320  vpImageIo::read(Icur, filename);
321 
322  if (opt_display) {
323  try{
324  // Display size is automatically defined by the image (I) size
325  display[1].init(Icur, (int)(100+Iref.getWidth()), 100,"Display current image") ;
326  vpDisplay::display(Icur) ;
327  vpDisplay::flush(Icur) ;
328  }
329  catch(...)
330  {
331  vpERROR_TRACE("Error while displaying the image") ;
332  exit(-1);
333  }
334  }
335 
336  for (iter = 1 ; iter < 30 ; iter++)
337  {
338  std::cout <<"----------------------------------------------------------"<<std::endl;
339  // set the new image name
340  s.str("");
341  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
342  filename = vpIoTools::createFilePath(dirname, s.str());
343  // read the image
344  vpImageIo::read(Icur, filename);
345  if (opt_display) {
346  // Display the image
347  vpDisplay::display(Iref) ;
348  vpDisplay::display(Icur) ;
349  }
350 
351  nbrPair = surf.matchPoint(Icur);
352  std::cout << "Number of matched point : " << nbrPair <<std::endl;
353 
354  if (opt_display)
355  {
356  // Display the matched features
357  surf.display(Iref, Icur, 7);
358  vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::red);
359  vpDisplay::flush(Iref) ;
360  vpDisplay::flush(Icur) ;
361  }
362  }
363  return 0;
364  }
365  catch(vpException &e) {
366  std::cout << "Catch an exception: " << e << std::endl;
367  return 1;
368  }
369 }
370 
371 #else
372 int
373 main()
374 {
375 #if ( ! (defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) )
376  vpERROR_TRACE("You do not have X11, GTK or GDI display functionalities...");
377 #else
378  vpERROR_TRACE("You do not have 1.1.0 <= OpenCV < 3.0.0 that contains opencv_nonfree component...");
379 #endif
380 }
381 
382 #endif
double get_i() const
Definition: vpImagePoint.h:199
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1157
#define vpERROR_TRACE
Definition: vpDebug.h:391
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:153
error that can be emited by ViSP classes.
Definition: vpException.h:73
unsigned int matchPoint(const vpImage< unsigned char > &I)
void display(const vpImage< unsigned char > &Iref, const vpImage< unsigned char > &Icurrent, unsigned int size=3)
static const vpColor green
Definition: vpColor.h:166
static void flush(const vpImage< unsigned char > &I)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:76
static const vpColor red
Definition: vpColor.h:163
Class that implements the SURF key points and technics thanks to OpenCV library.
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1366
static void display(const vpImage< unsigned char > &I)
double get_j() const
Definition: vpImagePoint.h:210
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:138
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
unsigned int buildReference(const vpImage< unsigned char > &I)
#define vpCTRACE
Definition: vpDebug.h:337
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:205
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
unsigned int getWidth() const
Definition: vpImage.h:226
void set_ij(const double ii, const double jj)
Definition: vpImagePoint.h:185