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