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  *****************************************************************************/
39 /*!
40   \file keyPointSurf.cpp
41 
42   \brief Tracking of Surf key-points.
43 */
44 
45 /*!
46   \example keyPointSurf.cpp
47 
48   Tracking of Surf key-points.
49 */
50 
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 
60 #include <visp3/vision/vpKeyPointSurf.h>
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 
78 /*!
79 
80   Print the program options.
81 
82   \param name : Program name.
83   \param badparam : Bad parameter name.
84   \param ipath : Input image path.
85 
86 */
usage(const char * name,const char * badparam,std::string ipath)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 }
118 /*!
119 
120   Set the program options.
121 
122   \param argc : Command line number of parameters.
123   \param argv : Array of command line parameters.
124   \param ipath : Input image path.
125   \param click_allowed : Mouse click activation.
126   \param display : Display activation.
127 
128   \return false if the program has to be stopped, true otherwise.
129 
130 */
getOptions(int argc,const char ** argv,std::string & ipath,bool & click_allowed,bool & display)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 
main(int argc,const char ** argv)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
223     vpImage<unsigned char> Iref;
224     vpImage<unsigned char> Icur;
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
main()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
379