Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
trackKltOpencv.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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 https://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 * Example of dot tracking.
32 */
38
39#include <iostream>
40
41#include <visp3/core/vpConfig.h>
42
43#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_DISPLAY)
44
45#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
46
47#include <vector>
48
49#include <visp3/core/vpImage.h>
50#include <visp3/core/vpIoTools.h>
51#include <visp3/gui/vpDisplayFactory.h>
52#include <visp3/io/vpImageIo.h>
53#include <visp3/io/vpParseArgv.h>
54#include <visp3/klt/vpKltOpencv.h>
55
56// List of allowed command line options
57#define GETOPTARGS "cdf:i:l:p:s:h"
58
59#ifdef ENABLE_VISP_NAMESPACE
60using namespace VISP_NAMESPACE_NAME;
61#endif
62
63void usage(const char *name, const char *badparam, const std::string &ipath, const std::string &ppath, unsigned first,
64 unsigned last, unsigned step);
65bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first, unsigned &last,
66 unsigned &step, bool &click_allowed, bool &display);
73
88void usage(const char *name, const char *badparam, const std::string &ipath, const std::string &ppath, unsigned first,
89 unsigned last, unsigned step)
90{
91#if defined(VISP_HAVE_DATASET)
92#if VISP_HAVE_DATASET_VERSION >= 0x030600
93 std::string ext("png");
94#else
95 std::string ext("pgm");
96#endif
97#else
98 // We suppose that the user will download a recent dataset
99 std::string ext("png");
100#endif
101 fprintf(stdout, "\n\
102Example of KLT tracking using OpenCV library.\n\
103\n\
104SYNOPSIS\n\
105 %s [-i <test image path>] [-p <personal image path>]\n\
106 [-f <first image>] [-l <last image>] [-s <step>]\n\
107 [-c] [-d] [-h]\n",
108 name);
109
110 fprintf(stdout, "\n\
111OPTIONS: Default\n\
112 -i <input image path> %s\n\
113 Set image input path.\n\
114 From this path read images \n\
115 \"mire-2/image.%%04d.%s\". These \n\
116 images come from visp-images-x.y.z.tar.gz available \n\
117 on the ViSP website.\n\
118 Setting the VISP_INPUT_IMAGE_PATH environment\n\
119 variable produces the same behaviour than using\n\
120 this option.\n\
121 \n\
122 -p <personal image path> %s\n\
123 Specify a personal sequence containing images \n\
124 to process.\n\
125 By image sequence, we mean one file per image.\n\
126 Example : \"/Temp/visp-images/mire-2/image.%%04d.%s\"\n\
127 %%04d is for the image numbering.\n\
128 \n\
129 -f <first image> %u\n\
130 First image number of the sequence.\n\
131 \n\
132 -l <last image> %u\n\
133 Last image number of the sequence.\n\
134 \n\
135 -s <step> %u\n\
136 Step between two images.\n\
137\n\
138 -c\n\
139 Disable the mouse click. Useful to automate the \n\
140 execution of this program without human intervention.\n\
141\n\
142 -d \n\
143 Turn off the display.\n\
144\n\
145 -h\n\
146 Print the help.\n",
147 ipath.c_str(), ext.c_str(), ppath.c_str(), ext.c_str(), first, last, step);
148
149 if (badparam)
150 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
151}
152
170bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first, unsigned &last,
171 unsigned &step, bool &click_allowed, bool &display)
172{
173 const char *optarg_;
174 int c;
175 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
176
177 switch (c) {
178 case 'c':
179 click_allowed = false;
180 break;
181 case 'd':
182 display = false;
183 break;
184 case 'i':
185 ipath = optarg_;
186 break;
187 case 'p':
188 ppath = optarg_;
189 break;
190 case 'f':
191 first = static_cast<unsigned int>(atoi(optarg_));
192 break;
193 case 'l':
194 last = static_cast<unsigned int>(atoi(optarg_));
195 break;
196 case 's':
197 step = static_cast<unsigned int>(atoi(optarg_));
198 break;
199 case 'h':
200 usage(argv[0], nullptr, ipath, ppath, first, last, step);
201 return false;
202
203 default:
204 usage(argv[0], optarg_, ipath, ppath, first, last, step);
205 return false;
206 }
207 }
208
209 if ((c == 1) || (c == -1)) {
210 // standalone param or error
211 usage(argv[0], nullptr, ipath, ppath, first, last, step);
212 std::cerr << "ERROR: " << std::endl;
213 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
214 return false;
215 }
216
217 return true;
218}
219
220int main(int argc, const char **argv)
221{
222 try {
223 std::string env_ipath;
224 std::string opt_ipath;
225 std::string ipath;
226 std::string opt_ppath;
227 std::string dirname;
228 std::string filename;
229 unsigned opt_first = 1;
230 unsigned opt_last = 500;
231 unsigned opt_step = 1;
232 bool opt_click_allowed = true;
233 bool opt_display = true;
234
235#if defined(VISP_HAVE_DATASET)
236#if VISP_HAVE_DATASET_VERSION >= 0x030600
237 std::string ext("png");
238#else
239 std::string ext("pgm");
240#endif
241#else
242 // We suppose that the user will download a recent dataset
243 std::string ext("png");
244#endif
245
246 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
247 // environment variable value
249
250 // Set the default input path
251 if (!env_ipath.empty())
252 ipath = env_ipath;
253
254 // Read the command line options
255 if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_first, opt_last, opt_step, opt_click_allowed,
256 opt_display) == false) {
257 return EXIT_FAILURE;
258 }
259
260 // Get the option values
261 if (!opt_ipath.empty())
262 ipath = opt_ipath;
263
264 // Compare ipath and env_ipath. If they differ, we take into account
265 // the input path coming from the command line option
266 if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
267 if (ipath != env_ipath) {
268 std::cout << std::endl << "WARNING: " << std::endl;
269 std::cout << " Since -i <visp image path=" << ipath << "> "
270 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
271 << " we skip the environment variable." << std::endl;
272 }
273 }
274
275 // Test if an input path is set
276 if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty()) {
277 usage(argv[0], nullptr, ipath, opt_ppath, opt_first, opt_last, opt_step);
278 std::cerr << std::endl << "ERROR:" << std::endl;
279 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
280 << " environment variable to specify the location of the " << std::endl
281 << " image path where test images are located." << std::endl
282 << " Use -p <personal image path> option if you want to " << std::endl
283 << " use personal images." << std::endl
284 << std::endl;
285
286 return EXIT_FAILURE;
287 }
288
289 // Declare an image, this is a gray level image (unsigned char)
290 // it size is not defined yet, it will be defined when the image will
291 // read on the disk
292 vpImage<unsigned char> vpI; // This is a ViSP image used for display only
293 cv::Mat cvI;
294 vpDisplay *display = nullptr;
295
296 unsigned iter = opt_first;
297
298 if (opt_ppath.empty()) {
299
300 // Warning :
301 // The image sequence is not provided with the ViSP package
302 // therefore the program will return an error :
303 // !! couldn't read file visp-images/mire-2/image.0001.png
304 //
305 // ViSP dataset is available on the visp www site
306 // https://visp.inria.fr/download/.
307
308 // Set the path location of the image sequence
309 dirname = vpIoTools::createFilePath(ipath, "mire-2");
310
311 // Build the name of the image file
312 std::string name = vpIoTools::formatString("image.%04d." + ext, iter);
313 filename = vpIoTools::createFilePath(dirname, name);
314 }
315 else {
316 filename = vpIoTools::formatString(opt_ppath, iter);
317 }
318
319 // Read the image named "filename", and put the bitmap into the image structure I.
320 // I is initialized to the correct size
321 //
322 // vpImageIo::read() may throw various exception if, for example,
323 // the file does not exist, or if the memory cannot be allocated
324 try {
325 std::cout << "Load: " << filename << std::endl;
326
327 // Load a ViSP image used for the display
328 vpImageIo::read(vpI, filename);
329 vpImageConvert::convert(vpI, cvI);
330 }
331 catch (...) {
332 // If an exception is thrown by vpImageIo::read() it will result in the end of the program.
333 std::cerr << std::endl << "ERROR:" << std::endl;
334 std::cerr << " Cannot read " << filename << std::endl;
335 if (opt_ppath.empty()) {
336 std::cerr << " Check your -i " << ipath << " option " << std::endl
337 << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
338 }
339 else {
340 std::cerr << " Check your -p " << opt_ppath << " option " << std::endl;
341 }
342 return EXIT_FAILURE;
343 }
344
345
346 if (opt_display) {
347 // We open a window using either X11, GTK, OpenCV or GDI.
349 // Display size is automatically defined by the image (I) size
350 display->init(vpI, 100, 100, "Display...");
351 // Display the image
352 // The image class has a member that specify a pointer toward
353 // the display that has been initialized in the display declaration
354 // therefore is is no longer necessary to make a reference to the
355 // display variable.
357 vpDisplay::flush(vpI);
358 }
359
360 // KLT tracker
362
363 // Event manager
364 // tracker.setOnNewFeature(&newFeature);
365 // tracker.setOnFeatureLost(&lostFeature);
366 // tracker.setIsFeatureValid(&isValid);
367
368 // Tracker parameters
369 tracker.setTrackerId(1);
370 // tracker.setOnMeasureFeature(&modifyFeature);
371 tracker.setMaxFeatures(200);
372 tracker.setWindowSize(10);
373 tracker.setQuality(0.01);
374 tracker.setMinDistance(15);
375 tracker.setHarrisFreeParameter(0.04);
376 tracker.setBlockSize(9);
377 tracker.setUseHarris(1);
378 tracker.setPyramidLevels(3);
379
380 // Point detection using Harris. In input we have an OpenCV IPL image
381 tracker.initTracking(cvI);
382
383 if (opt_display) {
384 // Plot the Harris points on ViSP image
385 tracker.display(vpI, vpColor::red);
386 }
387
388 bool quit = false;
389
390 // Tracking is now initialized. We can start the tracker.
391 while ((iter < opt_last) && (!quit)) {
392 // set the new image name
393 if (opt_ppath.empty()) {
394 std::string name = vpIoTools::formatString("image.%04d." + ext, iter);
395 filename = vpIoTools::createFilePath(dirname, name);
396 }
397 else {
398 filename = vpIoTools::formatString(opt_ppath, iter);
399 }
400 // read the image
401 vpImageIo::read(vpI, filename);
402 vpImageConvert::convert(vpI, cvI);
403
404 // track the dot and returns its coordinates in the image
405 // results are given in float since many many are usually considered
406 //
407 // an exception is thrown by the track method if
408 // - dot is lost
409
410 if (opt_display) {
411 // Display the image
413 }
414
415 std::cout << "Tracking on image: " << filename << std::endl;
416 double time = vpTime::measureTimeMs();
417 // Tracking of the detected points
418 tracker.track(cvI);
419 std::cout << "Tracking performed in " << vpTime::measureTimeMs() - time << " ms" << std::endl;
420
421 if (opt_display) {
422 // Display the tracked points
423 tracker.display(vpI, vpColor::red);
424 vpDisplay::displayText(vpI, 20, 20, "Click to quit...", vpColor::red);
425 if (vpDisplay::getClick(vpI, false)) {
426 quit = true;
427 }
428 vpDisplay::flush(vpI);
429 }
430 iter += opt_step;
431 }
432 if (opt_display && opt_click_allowed && !quit) {
433 std::cout << "\nA click to exit..." << std::endl;
434 // Wait for a blocking mouse click
436 }
437 if (display) {
438 delete display;
439 }
440 return EXIT_SUCCESS;
441 }
442 catch (const vpException &e) {
443 std::cout << "Catch an exception: " << e << std::endl;
444 return EXIT_FAILURE;
445 }
446}
447#else
448int main()
449{
450 std::cout << "You do not have OpenCV functionalities to display images..." << std::endl;
451 std::cout << "Tip:" << std::endl;
452 std::cout << "- Install OpenCV, configure again ViSP using cmake and build again this example" << std::endl;
453 return EXIT_SUCCESS;
454}
455#endif
456#else
457#include <iostream>
458
459int main()
460{
461 std::cout << "visp_klt module or X11, GTK, GDI or OpenCV display functionalities are required..." << std::endl;
462}
463
464#endif
static const vpColor red
Definition vpColor.h:198
Class that defines generic functionalities for display.
Definition vpDisplay.h:171
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void flush(const vpImage< unsigned char > &I)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
error that can be emitted by ViSP classes.
Definition vpException.h:60
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
Definition vpImage.h:131
static std::string getViSPImagesDataPath()
static std::string formatString(const std::string &name, unsigned int val)
static std::string createFilePath(const std::string &parent, const std::string &child)
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV. Thus to enable this ...
Definition vpKltOpencv.h:83
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.
VISP_EXPORT double measureTimeMs()