Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
mbtKltTracking.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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 MBT KLT Tracking.
32 */
33
39
40#include <iostream>
41#include <visp3/core/vpConfig.h>
42
43#if defined(VISP_HAVE_MODULE_MBT) && defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && \
44 defined(VISP_HAVE_DISPLAY) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
45
46#include <visp3/core/vpDebug.h>
47#include <visp3/core/vpHomogeneousMatrix.h>
48#include <visp3/core/vpIoTools.h>
49#include <visp3/core/vpMath.h>
50#include <visp3/gui/vpDisplayD3D.h>
51#include <visp3/gui/vpDisplayGDI.h>
52#include <visp3/gui/vpDisplayGTK.h>
53#include <visp3/gui/vpDisplayOpenCV.h>
54#include <visp3/gui/vpDisplayX.h>
55#include <visp3/io/vpImageIo.h>
56#include <visp3/io/vpParseArgv.h>
57#include <visp3/io/vpVideoReader.h>
58#include <visp3/mbt/vpMbKltTracker.h>
59
60#define GETOPTARGS "x:m:i:n:de:chtfolwv"
61
62#ifdef ENABLE_VISP_NAMESPACE
63using namespace VISP_NAMESPACE_NAME;
64#endif
65
66void usage(const char *name, const char *badparam)
67{
68#if defined(VISP_HAVE_DATASET)
69#if VISP_HAVE_DATASET_VERSION >= 0x030600
70 std::string ext("png");
71#else
72 std::string ext("pgm");
73#endif
74#else
75 // We suppose that the user will download a recent dataset
76 std::string ext("png");
77#endif
78 fprintf(stdout, "\n\
79Example of tracking based on the 3D model.\n\
80\n\
81SYNOPSIS\n\
82 %s [-i <test image path>] [-x <config file>]\n\
83 [-m <model name>] [-n <initialisation file base name>] [-e <last frame index>]\n\
84 [-t] [-c] [-d] [-h] [-f] [-o] [-w] [-l] [-v]\n",
85 name);
86
87 fprintf(stdout, "\n\
88OPTIONS: \n\
89 -i <input image path> \n\
90 Set image input path.\n\
91 From this path read images \n\
92 \"mbt/cube/image%%04d.%s\". These \n\
93 images come from visp-images-x.y.z.tar.gz available \n\
94 on the ViSP website.\n\
95 Setting the VISP_INPUT_IMAGE_PATH environment\n\
96 variable produces the same behaviour than using\n\
97 this option.\n\
98\n\
99 -x <config file> \n\
100 Set the config file (the xml file) to use.\n\
101 The config file is used to specify the parameters of the tracker.\n\
102\n\
103 -m <model name> \n\
104 Specify the name of the file of the model\n\
105 The model can either be a vrml model (.wrl) or a .cao file.\n\
106\n\
107 -e <last frame index> \n\
108 Specify the index of the last frame. Once reached, the tracking is stopped\n\
109\n\
110 -f \n\
111 Do not use the vrml model, use the .cao one. These two models are \n\
112 equivalent and comes from ViSP-images-x.y.z.tar.gz available on the ViSP\n\
113 website. However, the .cao model allows to use the 3d model based tracker \n\
114 without Coin.\n\
115\n\
116 -n <initialisation file base name> \n\
117 Base name of the initialisation file. The file will be 'base_name'.init .\n\
118 This base name is also used for the Optional picture specifying where to \n\
119 click (a .ppm picture).\n\
120\n\
121 -t \n\
122 Turn off the display of the the klt points. \n\
123\n\
124 -d \n\
125 Turn off the display.\n\
126\n\
127 -c\n\
128 Disable the mouse click. Useful to automate the \n\
129 execution of this program without human intervention.\n\
130\n\
131 -o\n\
132 Use Ogre3D for visibility tests\n\
133\n\
134 -w\n\
135 When Ogre3D is enable [-o] show Ogre3D configuration dialog thatallows to set the renderer.\n\
136\n\
137 -l\n\
138 Use the scanline for visibility tests.\n\
139\n\
140 -v\n\
141 Compute covariance matrix.\n\
142\n\
143 -h \n\
144 Print the help.\n\n",
145 ext.c_str());
146
147 if (badparam)
148 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
149}
150
151bool getOptions(int argc, const char **argv, std::string &ipath, std::string &configFile, std::string &modelFile,
152 std::string &initFile, long &lastFrame, bool &displayKltPoints, bool &click_allowed, bool &display,
153 bool &cao3DModel, bool &useOgre, bool &showOgreConfigDialog, bool &useScanline, bool &computeCovariance)
154{
155 const char *optarg_;
156 int c;
157 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
158
159 switch (c) {
160 case 'e':
161 lastFrame = atol(optarg_);
162 break;
163 case 'i':
164 ipath = optarg_;
165 break;
166 case 'x':
167 configFile = optarg_;
168 break;
169 case 'm':
170 modelFile = optarg_;
171 break;
172 case 'n':
173 initFile = optarg_;
174 break;
175 case 't':
176 displayKltPoints = false;
177 break;
178 case 'f':
179 cao3DModel = true;
180 break;
181 case 'c':
182 click_allowed = false;
183 break;
184 case 'd':
185 display = false;
186 break;
187 case 'o':
188 useOgre = true;
189 break;
190 case 'l':
191 useScanline = true;
192 break;
193 case 'w':
194 showOgreConfigDialog = true;
195 break;
196 case 'v':
197 computeCovariance = true;
198 break;
199 case 'h':
200 usage(argv[0], nullptr);
201 return false;
202
203 default:
204 usage(argv[0], optarg_);
205 return false;
206 }
207 }
208
209 if ((c == 1) || (c == -1)) {
210 // standalone param or error
211 usage(argv[0], nullptr);
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_configFile;
227 std::string configFile;
228 std::string opt_modelFile;
229 std::string modelFile;
230 std::string opt_initFile;
231 std::string initFile;
232 long opt_lastFrame = -1;
233 bool displayKltPoints = true;
234 bool opt_click_allowed = true;
235 bool opt_display = true;
236 bool cao3DModel = false;
237 bool useOgre = false;
238 bool showOgreConfigDialog = false;
239 bool useScanline = false;
240 bool computeCovariance = false;
241 bool quit = false;
242
243#if defined(VISP_HAVE_DATASET)
244#if VISP_HAVE_DATASET_VERSION >= 0x030600
245 std::string ext("png");
246#else
247 std::string ext("pgm");
248#endif
249#else
250 // We suppose that the user will download a recent dataset
251 std::string ext("png");
252#endif
253
254 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
255 // environment variable value
257
258 // Set the default input path
259 if (!env_ipath.empty())
260 ipath = env_ipath;
261
262 // Read the command line options
263 if (!getOptions(argc, argv, opt_ipath, opt_configFile, opt_modelFile, opt_initFile, opt_lastFrame, displayKltPoints,
264 opt_click_allowed, opt_display, cao3DModel, useOgre, showOgreConfigDialog, useScanline,
265 computeCovariance)) {
266 return EXIT_FAILURE;
267 }
268
269 // Test if an input path is set
270 if (opt_ipath.empty() && env_ipath.empty()) {
271 usage(argv[0], nullptr);
272 std::cerr << std::endl << "ERROR:" << std::endl;
273 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
274 << " environment variable to specify the location of the " << std::endl
275 << " image path where test images are located." << std::endl
276 << std::endl;
277
278 return EXIT_FAILURE;
279 }
280
281 // Get the option values
282 if (!opt_ipath.empty())
283 ipath = vpIoTools::createFilePath(opt_ipath, "mbt/cube/image%04d." + ext);
284 else
285 ipath = vpIoTools::createFilePath(env_ipath, "mbt/cube/image%04d." + ext);
286
287 if (!opt_configFile.empty())
288 configFile = opt_configFile;
289 else if (!opt_ipath.empty())
290 configFile = vpIoTools::createFilePath(opt_ipath, "mbt/cube.xml");
291 else
292 configFile = vpIoTools::createFilePath(env_ipath, "mbt/cube.xml");
293
294 if (!opt_modelFile.empty()) {
295 modelFile = opt_modelFile;
296 }
297 else {
298 std::string modelFileCao = "mbt/cube.cao";
299 std::string modelFileWrl = "mbt/cube.wrl";
300
301 if (!opt_ipath.empty()) {
302 if (cao3DModel) {
303 modelFile = vpIoTools::createFilePath(opt_ipath, modelFileCao);
304 }
305 else {
306#ifdef VISP_HAVE_COIN3D
307 modelFile = vpIoTools::createFilePath(opt_ipath, modelFileWrl);
308#else
309 std::cerr << "Coin is not detected in ViSP. Use the .cao model instead." << std::endl;
310 modelFile = vpIoTools::createFilePath(opt_ipath, modelFileCao);
311#endif
312 }
313 }
314 else {
315 if (cao3DModel) {
316 modelFile = vpIoTools::createFilePath(env_ipath, modelFileCao);
317 }
318 else {
319#ifdef VISP_HAVE_COIN3D
320 modelFile = vpIoTools::createFilePath(env_ipath, modelFileWrl);
321#else
322 std::cerr << "Coin is not detected in ViSP. Use the .cao model instead." << std::endl;
323 modelFile = vpIoTools::createFilePath(env_ipath, modelFileCao);
324#endif
325 }
326 }
327 }
328
329 if (!opt_initFile.empty())
330 initFile = opt_initFile;
331 else if (!opt_ipath.empty())
332 initFile = vpIoTools::createFilePath(opt_ipath, "mbt/cube");
333 else
334 initFile = vpIoTools::createFilePath(env_ipath, "mbt/cube");
335
337 vpVideoReader reader;
338
339 reader.setFileName(ipath);
340 try {
341 reader.open(I);
342 }
343 catch (...) {
344 std::cout << "Cannot open sequence: " << ipath << std::endl;
345 return EXIT_FAILURE;
346 }
347
348 if (opt_lastFrame > 1 && opt_lastFrame < reader.getLastFrameIndex())
349 reader.setLastFrameIndex(opt_lastFrame);
350
351 reader.acquire(I);
352
353// initialise a display
354#if defined(VISP_HAVE_X11)
355 vpDisplayX display;
356#elif defined(VISP_HAVE_GDI)
357 vpDisplayGDI display;
358#elif defined(HAVE_OPENCV_HIGHGUI)
359 vpDisplayOpenCV display;
360#elif defined(VISP_HAVE_D3D9)
361 vpDisplayD3D display;
362#elif defined(VISP_HAVE_GTK)
363 vpDisplayGTK display;
364#else
365 opt_display = false;
366#endif
367 if (opt_display) {
368#if defined(VISP_HAVE_DISPLAY)
369 display.init(I, 100, 100, "Test tracking");
370#endif
373 }
374
377
378 // Load tracker config file (camera parameters and moving edge settings)
380
381#if defined(VISP_HAVE_PUGIXML)
382 // From the xml file
383 tracker.loadConfigFile(configFile);
384#else
385 // Corresponding parameters manually set to have an example code
386 // By setting the parameters:
387 cam.initPersProjWithoutDistortion(547, 542, 338, 234);
388
389 vpKltOpencv klt;
390 klt.setMaxFeatures(10000);
391 klt.setWindowSize(5);
392 klt.setQuality(0.01);
393 klt.setMinDistance(5);
394 klt.setHarrisFreeParameter(0.01);
395 klt.setBlockSize(3);
396 klt.setPyramidLevels(3);
397
398 tracker.setCameraParameters(cam);
399 tracker.setKltOpencv(klt);
400 tracker.setKltMaskBorder(5);
401 tracker.setAngleAppear(vpMath::rad(65));
402 tracker.setAngleDisappear(vpMath::rad(75));
403
404 // Specify the clipping to use
405 tracker.setNearClippingDistance(0.01);
406 tracker.setFarClippingDistance(0.90);
407 tracker.setClipping(tracker.getClipping() | vpMbtPolygon::FOV_CLIPPING);
408// tracker.setClipping(tracker.getClipping() | vpMbtPolygon::LEFT_CLIPPING |
409// vpMbtPolygon::RIGHT_CLIPPING | vpMbtPolygon::UP_CLIPPING |
410// vpMbtPolygon::DOWN_CLIPPING); // Equivalent to FOV_CLIPPING
411#endif
412
413 // Display the klt points
414 tracker.setDisplayFeatures(displayKltPoints);
415
416 // Tells if the tracker has to use Ogre3D for visibility tests
417 tracker.setOgreVisibilityTest(useOgre);
418 if (useOgre)
419 tracker.setOgreShowConfigDialog(showOgreConfigDialog);
420
421 // Tells if the tracker has to use the scanline visibility tests
422 tracker.setScanLineVisibilityTest(useScanline);
423
424 // Tells if the tracker has to compute the covariance matrix
425 tracker.setCovarianceComputation(computeCovariance);
426
427 // Retrieve the camera parameters from the tracker
428 tracker.getCameraParameters(cam);
429
430 // Loop to position the cube
431 if (opt_display && opt_click_allowed) {
432 while (!vpDisplay::getClick(I, false)) {
434 vpDisplay::displayText(I, 15, 10, "click after positioning the object", vpColor::red);
436 }
437 }
438
439 // Load the 3D model (either a vrml file or a .cao file)
440 tracker.loadModel(modelFile);
441
442 // Initialise the tracker by clicking on the image
443 // This function looks for
444 // - a ./cube/cube.init file that defines the 3d coordinates (in meter,
445 // in the object basis) of the points used for the initialisation
446 // - a ./cube/cube.ppm file to display where the user have to click
447 // (Optional, set by the third parameter)
448 if (opt_display && opt_click_allowed) {
449 tracker.initClick(I, initFile, true);
450 tracker.getPose(cMo);
451 // display the 3D model at the given pose
452 tracker.display(I, cMo, cam, vpColor::red);
453 }
454 else {
455 vpHomogeneousMatrix cMoi(0.02044769891, 0.1101505452, 0.5078963719, 2.063603907, 1.110231561, -0.4392789872);
456 tracker.initFromPose(I, cMoi);
457 }
458
459 // track the model
460 tracker.track(I);
461 tracker.getPose(cMo);
462
463 if (opt_display)
465
466 while (!reader.end()) {
467 // acquire a new image
468 reader.acquire(I);
469 // display the image
470 if (opt_display)
472
473 // Test to reset the tracker
474 if (reader.getFrameIndex() == reader.getFirstFrameIndex() + 10) {
475 vpTRACE("Test reset tracker");
476 if (opt_display)
478 tracker.resetTracker();
479
480#if defined(VISP_HAVE_PUGIXML)
481 tracker.loadConfigFile(configFile);
482#else
483 // Corresponding parameters manually set to have an example code
484 // By setting the parameters:
485 cam.initPersProjWithoutDistortion(547, 542, 338, 234);
486
487 vpKltOpencv klt;
488 klt.setMaxFeatures(10000);
489 klt.setWindowSize(5);
490 klt.setQuality(0.01);
491 klt.setMinDistance(5);
492 klt.setHarrisFreeParameter(0.01);
493 klt.setBlockSize(3);
494 klt.setPyramidLevels(3);
495
496 tracker.setCameraParameters(cam);
497 tracker.setKltOpencv(klt);
498 tracker.setKltMaskBorder(5);
499 tracker.setAngleAppear(vpMath::rad(65));
500 tracker.setAngleDisappear(vpMath::rad(75));
501
502 // Specify the clipping to use
503 tracker.setNearClippingDistance(0.01);
504 tracker.setFarClippingDistance(0.90);
505 tracker.setClipping(tracker.getClipping() | vpMbtPolygon::FOV_CLIPPING);
506// tracker.setClipping(tracker.getClipping() | vpMbtPolygon::LEFT_CLIPPING |
507// vpMbtPolygon::RIGHT_CLIPPING | vpMbtPolygon::UP_CLIPPING |
508// vpMbtPolygon::DOWN_CLIPPING); // Equivalent to FOV_CLIPPING
509#endif
510 tracker.loadModel(modelFile);
511 tracker.setCameraParameters(cam);
512 tracker.setOgreVisibilityTest(useOgre);
513 tracker.setScanLineVisibilityTest(useScanline);
514 tracker.setCovarianceComputation(computeCovariance);
515 tracker.initFromPose(I, cMo);
516 }
517
518 // Test to set an initial pose
519 if (reader.getFrameIndex() == reader.getFirstFrameIndex() + 50) {
520 cMo.buildFrom(0.0439540832, 0.0845870108, 0.5477322481, 2.179498458, 0.8611798108, -0.3491961946);
521 vpTRACE("Test set pose");
522 tracker.setPose(I, cMo);
523 // if (opt_display) {
524 // // display the 3D model
525 // tracker.display(I, cMo, cam, vpColor::darkRed);
526 // // display the frame
527 // vpDisplay::displayFrame (I, cMo, cam, 0.05);
532 // }
533 }
534
535 // track the object: stop tracking from frame 40 to 50
536 if (reader.getFrameIndex() - reader.getFirstFrameIndex() < 40 ||
537 reader.getFrameIndex() - reader.getFirstFrameIndex() >= 50) {
538 tracker.track(I);
539 tracker.getPose(cMo);
540 if (opt_display) {
541 // display the 3D model
542 tracker.display(I, cMo, cam, vpColor::darkRed);
543 // display the frame
544 vpDisplay::displayFrame(I, cMo, cam, 0.05);
545 }
546 }
547
548 if (opt_click_allowed) {
549 vpDisplay::displayText(I, 10, 10, "Click to quit", vpColor::red);
550 if (vpDisplay::getClick(I, false)) {
551 quit = true;
552 break;
553 }
554 }
555
556 if (computeCovariance) {
557 std::cout << "Covariance matrix: \n" << tracker.getCovarianceMatrix() << std::endl << std::endl;
558 }
559
560 if (opt_display)
562 }
563
564 std::cout << "Reached last frame: " << reader.getFrameIndex() << std::endl;
565
566 if (opt_click_allowed && !quit) {
568 }
569
570 reader.close();
571
572 return EXIT_SUCCESS;
573 }
574 catch (const vpException &e) {
575 std::cout << "Catch an exception: " << e << std::endl;
576 return EXIT_FAILURE;
577 }
578}
579
580#else
581
582int main()
583{
584 std::cout << "visp_mbt, visp_gui modules and OpenCV are required to run "
585 "this example."
586 << std::endl;
587 return EXIT_SUCCESS;
588}
589
590#endif
Generic class defining intrinsic camera parameters.
static const vpColor red
Definition vpColor.h:198
static const vpColor darkRed
Definition vpColor.h:199
Display for windows using Direct3D 3rd party. Thus to enable this class Direct3D should be installed....
Display for windows using GDI (available on any windows 32 platform).
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:135
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, const vpImagePoint &offset=vpImagePoint(0, 0), const std::string &frameName="", const vpColor &textColor=vpColor::black, const vpImagePoint &textOffset=vpImagePoint(15, 15))
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
Implementation of an homogeneous matrix and operations on such kind of matrices.
Definition of the vpImage class member functions.
Definition vpImage.h:131
static std::string getViSPImagesDataPath()
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
void setBlockSize(int blockSize)
void setQuality(double qualityLevel)
void setHarrisFreeParameter(double harris_k)
void setMaxFeatures(int maxCount)
void setMinDistance(double minDistance)
void setWindowSize(int winSize)
void setPyramidLevels(int pyrMaxLevel)
static double rad(double deg)
Definition vpMath.h:129
Model based tracker using only KLT.
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
void setLastFrameIndex(const long last_frame)
long getLastFrameIndex()
void open(vpImage< vpRGBa > &I) VP_OVERRIDE
void setFileName(const std::string &filename)
long getFirstFrameIndex()
void close() VP_OVERRIDE
long getFrameIndex() const
void acquire(vpImage< vpRGBa > &I) VP_OVERRIDE
#define vpTRACE
Definition vpDebug.h:450