Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
keyPointSurf.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Tracking of Surf key points.
33  *
34  * Authors:
35  * Nicolas Melchior
36  * Fabien Spindler
37  *
38  *****************************************************************************/
51 #include <iomanip>
52 #include <sstream>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <visp3/core/vpConfig.h>
56 #include <visp3/core/vpDebug.h>
57 #if ((defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) && \
58  defined(VISP_HAVE_OPENCV_NONFREE) && (VISP_HAVE_OPENCV_VERSION < 0x030000))
59 
61 
62 #include <visp3/core/vpImage.h>
63 #include <visp3/core/vpImagePoint.h>
64 #include <visp3/gui/vpDisplayGDI.h>
65 #include <visp3/gui/vpDisplayGTK.h>
66 #include <visp3/gui/vpDisplayX.h>
67 #include <visp3/io/vpImageIo.h>
68 
69 #include <visp3/core/vpIoTools.h>
70 #include <visp3/io/vpParseArgv.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 \"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", ipath.c_str());
114 
115  if (badparam)
116  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
117 }
131 bool getOptions(int argc, const char **argv, std::string &ipath, bool &click_allowed, bool &display)
132 {
133  const char *optarg_;
134  int c;
135  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
136 
137  switch (c) {
138  case 'c':
139  click_allowed = false;
140  break;
141  case 'd':
142  display = false;
143  break;
144  case 'i':
145  ipath = optarg_;
146  break;
147  case 'h':
148  usage(argv[0], NULL, ipath);
149  return false;
150  break;
151 
152  default:
153  usage(argv[0], optarg_, ipath);
154  return false;
155  break;
156  }
157  }
158 
159  if ((c == 1) || (c == -1)) {
160  // standalone param or error
161  usage(argv[0], NULL, ipath);
162  std::cerr << "ERROR: " << std::endl;
163  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
164  return false;
165  }
166 
167  return true;
168 }
169 
170 int main(int argc, const char **argv)
171 {
172  try {
173  std::string env_ipath;
174  std::string opt_ipath;
175  std::string ipath;
176  std::string dirname;
177  std::string filename;
178  bool opt_click_allowed = true;
179  bool opt_display = true;
180 
181  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
182  // 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, opt_display) == false) {
191  exit(-1);
192  }
193 
194  // Get the option values
195  if (!opt_ipath.empty())
196  ipath = opt_ipath;
197 
198  // Compare ipath and env_ipath. If they differ, we take into account
199  // the input path comming from the command line option
200  if (!opt_ipath.empty() && !env_ipath.empty()) {
201  if (ipath != env_ipath) {
202  std::cout << std::endl << "WARNING: " << std::endl;
203  std::cout << " Since -i <visp image path=" << ipath << "> "
204  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
205  << " we skip the environment variable." << std::endl;
206  }
207  }
208 
209  // Test if an input path is set
210  if (opt_ipath.empty() && env_ipath.empty()) {
211  usage(argv[0], NULL, ipath);
212  std::cerr << std::endl << "ERROR:" << std::endl;
213  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
214  << " environment variable to specify the location of the " << std::endl
215  << " image path where test images are located." << std::endl
216  << std::endl;
217  exit(-1);
218  }
219 
220  // Declare an image, this is a gray level image (unsigned char)
221  // it size is not defined yet, it will be defined when the image will
222  // read on the disk
225 
226  // Set the path location of the image sequence
227  dirname = vpIoTools::createFilePath(ipath, "cube");
228 
229  // Build the name of the image file
230  unsigned int iter = 0; // Image number
231  std::ostringstream s;
232  s.setf(std::ios::right, std::ios::adjustfield);
233  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
234  filename = vpIoTools::createFilePath(dirname, s.str());
235 
236  // Read the PGM image named "filename" on the disk, and put the
237  // bitmap into the image structure I. I is initialized to the
238  // correct size
239  //
240  // exception readPGM may throw various exception if, for example,
241  // the file does not exist, or if the memory cannot be allocated
242  try {
243  vpCTRACE << "Load: " << filename << std::endl;
244 
245  vpImageIo::read(Iref, filename);
246  } catch (...) {
247  // an exception is throwned if an exception from readPGM has been
248  // catched here this will result in the end of the program Note that
249  // another error message has been printed from readPGM to give more
250  // information about the error
251  std::cerr << std::endl << "ERROR:" << std::endl;
252  std::cerr << " Cannot read " << filename << std::endl;
253  std::cerr << " Check your -i " << ipath << " option " << std::endl
254  << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
255  exit(-1);
256  }
257 
258 // We open a window using either X11, GTK or GDI.
259 #if defined VISP_HAVE_X11
260  vpDisplayX display[2];
261 #elif defined VISP_HAVE_GTK
262  vpDisplayGTK display[2];
263 #elif defined VISP_HAVE_GDI
264  vpDisplayGDI display[2];
265 #endif
266 
267  if (opt_display) {
268  try {
269  // Display size is automatically defined by the image (I) size
270  display[0].init(Iref, 100, 100, "Display reference image");
271  vpDisplay::display(Iref);
272  vpDisplay::flush(Iref);
273  } catch (...) {
274  vpERROR_TRACE("Error while displaying the image");
275  exit(-1);
276  }
277  }
278 
279  vpImagePoint corners[2];
280  if (opt_display && opt_click_allowed) {
281  std::cout << "Click on the top left and the bottom right corners to "
282  "define the part of the image where the reference points "
283  "will be computed"
284  << std::endl;
285  for (unsigned int i = 0; i < 2; i++) {
286  vpDisplay::getClick(Iref, corners[i]);
287  std::cout << corners[i] << std::endl;
288  }
289  } else {
290  corners[0].set_ij(156, 209);
291  corners[1].set_ij(272, 378);
292  }
293 
294  if (opt_display) {
295  // Display the rectangle which defines the part of the image where the
296  // reference points are computed.
297  vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::green);
298  vpDisplay::flush(Iref);
299  }
300 
301  if (opt_click_allowed) {
302  std::cout << "Click on the image to continue" << std::endl;
303  vpDisplay::getClick(Iref);
304  }
305 
306  vpKeyPointSurf surf;
307  // unsigned int nbrRef;
308  unsigned int height, width;
309  height = (unsigned int)(corners[1].get_i() - corners[0].get_i());
310  width = (unsigned int)(corners[1].get_j() - corners[0].get_j());
311 
312  // Computes the reference points
313  /* nbrRef = */ surf.buildReference(Iref, corners[0], height, width);
314 
315  vpImageIo::read(Icur, filename);
316 
317  if (opt_display) {
318  try {
319  // Display size is automatically defined by the image (I) size
320  display[1].init(Icur, (int)(100 + Iref.getWidth()), 100, "Display current image");
321  vpDisplay::display(Icur);
322  vpDisplay::flush(Icur);
323  } catch (...) {
324  vpERROR_TRACE("Error while displaying the image");
325  exit(-1);
326  }
327  }
328 
329  for (iter = 1; iter < 30; iter++) {
330  std::cout << "----------------------------------------------------------" << std::endl;
331  // set the new image name
332  s.str("");
333  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
334  filename = vpIoTools::createFilePath(dirname, s.str());
335  // read the image
336  vpImageIo::read(Icur, filename);
337  if (opt_display) {
338  // Display the image
339  vpDisplay::display(Iref);
340  vpDisplay::display(Icur);
341  }
342 
343  unsigned int nbrPair = surf.matchPoint(Icur);
344  std::cout << "Number of matched point : " << nbrPair << std::endl;
345 
346  if (opt_display) {
347  // Display the matched features
348  surf.display(Iref, Icur, 7);
349  vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::red);
350  vpDisplay::flush(Iref);
351  vpDisplay::flush(Icur);
352  }
353  }
354  return EXIT_SUCCESS;
355  } catch (const vpException &e) {
356  std::cout << "Catch an exception: " << e << std::endl;
357  return EXIT_FAILURE;
358  }
359 }
360 
361 #else
362 int main()
363 {
364 #if (!(defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)))
365  std::cout << "You do not have X11, or GTK, or GDI (Graphical Device Interface) functionalities to display images..." << std::endl;
366  std::cout << "Tip if you are on a unix-like system:" << std::endl;
367  std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
368  std::cout << "Tip if you are on a windows-like system:" << std::endl;
369  std::cout << "- Install GDI, configure again ViSP using cmake and build again this example" << std::endl;
370 #else
371  std::cout << "You do not have OpenCV with non free module functionalities" << std::endl;
372  std::cout << "Tip:" << std::endl;
373  std::cout << "- Install OpenCV with non free module, configure again ViSP using cmake and build again this example" << std::endl;
374 #endif
375  return EXIT_SUCCESS;
376 }
377 
378 #endif
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:149
double get_i() const
Definition: vpImagePoint.h:203
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1365
#define vpERROR_TRACE
Definition: vpDebug.h:393
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:134
error that can be emited by ViSP classes.
Definition: vpException.h:71
static const vpColor green
Definition: vpColor.h:220
static void flush(const vpImage< unsigned char > &I)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
Class that implements the SURF key points and technics thanks to the OpenCV library.
static const vpColor red
Definition: vpColor.h:217
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1670
static void display(const vpImage< unsigned char > &I)
double get_j() const
Definition: vpImagePoint.h:214
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:134
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)
void set_ij(double ii, double jj)
Definition: vpImagePoint.h:188
#define vpCTRACE
Definition: vpDebug.h:338
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:87
unsigned int getWidth() const
Definition: vpImage.h:246