Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
trackMeLine.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 * Tracking of a line.
32 */
33
40
41#include <visp3/core/vpConfig.h>
42
43#if defined(VISP_HAVE_MODULE_ME) && defined(VISP_HAVE_DISPLAY)
44
45#include <visp3/core/vpColor.h>
46#include <visp3/core/vpImage.h>
47#include <visp3/core/vpImagePoint.h>
48#include <visp3/core/vpIoTools.h>
49#include <visp3/gui/vpDisplayFactory.h>
50#include <visp3/io/vpParseArgv.h>
51#include <visp3/io/vpVideoReader.h>
52#include <visp3/io/vpVideoWriter.h>
53#include <visp3/me/vpMeLine.h>
54#include <visp3/visual_features/vpFeatureBuilder.h>
55#include <visp3/visual_features/vpFeatureLine.h>
56
57// List of allowed command line options
58#define GETOPTARGS "Acdf:hi:l:p:r:s:S:t:T:vw:y"
59
60#ifdef ENABLE_VISP_NAMESPACE
61using namespace VISP_NAMESPACE_NAME;
62#endif
63
64void usage(const char *name, const char *badparam, const std::string &video_in_ipath, const std::string &video_in_ppath,
65 unsigned video_in_first, int video_in_last, int video_in_step, int me_range, int me_sample_step,
66 int me_threshold, unsigned int &sleep_ms);
67bool getOptions(int argc, const char **argv, std::string &video_in_ipath, std::string &video_in_ppath,
68 int &video_in_first, int &video_in_last, int &video_in_step,
69 bool &click_allowed, bool &display, bool &display_scale_auto,
70 std::string &video_out_save, int &me_range, int &me_sample_step, int &me_threshold, bool &step_by_step,
71 unsigned int &sleep_ms, bool &verbose);
72
88void usage(const char *name, const char *badparam, const std::string &video_in_ipath, const std::string &video_in_ppath,
89 unsigned video_in_first, int video_in_last, int video_in_step, int me_range, int me_sample_step,
90 int me_threshold, unsigned int &sleep_ms)
91{
92#if defined(VISP_HAVE_DATASET)
93#if VISP_HAVE_DATASET_VERSION >= 0x030600
94 std::string ext("png");
95#else
96 std::string ext("pgm");
97#endif
98#else
99 // We suppose that the user will download a recent dataset
100 std::string ext("png");
101#endif
102 fprintf(stdout, "\n\
103Tracking of a line.\n\
104\n\
105SYNOPSIS\n\
106 %s [-i <visp dataset directory>] [-p <personal image path>]\n\
107 [-f <video first image>] [-l <video last image>] [-s <video step>]\n\
108 [-r <moving-edge range] [-t <moving-edge threshold] [-S <moving-edge sample step>]\n\
109 [-w <output images sequence name>] [-T <sleep ms>]\n\
110 [-c] [-d] [-A] [-y] [-v] [-h]\n", name);
111
112 fprintf(stdout, "\n\
113OPTIONS: Default\n\
114 -i <visp dataset directory> %s\n\
115 Set image input path.\n\
116 From this path read \"line/image.%%04d.%s\" images. \n\
117 Setting the VISP_INPUT_IMAGE_PATH environment variable\n\
118 produces the same behaviour than using this option.\n\
119 \n\
120 -p <personal image path> %s\n\
121 Specify a personal sequence containing images \n\
122 to process.\n\
123 By image sequence, we mean one file per image.\n\
124 Example : \"C:/Temp/visp-images/line/image.%%04d.%s\"\n\
125 %%04d is for the image numbering.\n\
126 \n\
127 -f <video first image> %d\n\
128 First image number to process.\n\
129 Set -1 to process the first image of the sequence.\n\
130 \n\
131 -l <video last image> %d\n\
132 Last image number to process. \n\
133 Set -1 to process images until the last image of the\n\
134 sequence.\n\
135 \n\
136 -s <video step> %d\n\
137 Step between two images.\n\
138 \n\
139 -r <moving-edge range> %d\n\
140 Moving-edge range.\n\
141 Increase value to consider large displacement. \n\
142 When set to -1, use default value. \n\
143 \n\
144 -S <moving-edge sample step> %d\n\
145 Moving-edge sample step.\n\
146 Distance between two moving-edges samples in degrees. \n\
147 When set to -1, use default value. \n\
148 \n\
149 -t <moving-edge threshold> %d\n\
150 Moving-edge threshold corresponding to the minimum \n\
151 contrast to consider. Value in range [0 ; 255] \n\
152 When set to -1, use default value. \n\
153 \n\
154 -c\n\
155 Disable the mouse click. Useful to automate the \n\
156 execution of this program without human intervention.\n\
157 \n\
158 -d \n\
159 Turn off the display.\n\
160 \n\
161 -y \n\
162 Enable step-by-step mode waiting for a mouse click to\n\
163 process next image.\n\
164 \n\
165 -T %d \n\
166 Sleep time in ms before processing next image.\n\
167 Allows to slow down the image processing. \n\
168 \n\
169 -w <output images sequence name> \n\
170 Save images with tracking results in overlay.\n\
171 Example: \"result/I%%04d.png\" \n\
172 \n\
173 -A \n\
174 When display is activated using -d option, enable\n\
175 windows auto scaling to fit the screen size. \n\
176 \n\
177 -v \n\
178 Enable verbosity.\n\
179 \n\
180 -h\n\
181 Print the help.\n",
182 video_in_ipath.c_str(), ext.c_str(), video_in_ppath.c_str(), ext.c_str(), video_in_first, video_in_last,
183 video_in_step, me_range, me_sample_step, me_threshold, sleep_ms);
184
185 if (badparam) {
186 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
187 }
188}
189
212bool getOptions(int argc, const char **argv, std::string &video_in_ipath, std::string &video_in_ppath,
213 int &video_in_first, int &video_in_last, int &video_in_step,
214 bool &click_allowed, bool &display, bool &display_scale_auto,
215 std::string &video_out_save, int &me_range, int &me_sample_step, int &me_threshold, bool &step_by_step,
216 unsigned int &sleep_ms, bool &verbose)
217{
218 const char *optarg_;
219 int c;
220 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
221
222 switch (c) {
223 case 'A':
224 display_scale_auto = true;
225 break;
226 case 'c':
227 click_allowed = false;
228 break;
229 case 'd':
230 display = false;
231 break;
232 case 'f':
233 video_in_first = atoi(optarg_);
234 break;
235 case 'i':
236 video_in_ipath = std::string(optarg_);
237 break;
238 case 'l':
239 video_in_last = atoi(optarg_);
240 break;
241 case 'p':
242 video_in_ppath = std::string(optarg_);
243 break;
244 case 'r':
245 me_range = atoi(optarg_);
246 break;
247 case 's':
248 video_in_step = atoi(optarg_);
249 break;
250 case 'S':
251 me_sample_step = atoi(optarg_);
252 break;
253 case 't':
254 me_threshold = atoi(optarg_);
255 break;
256 case 'T':
257 sleep_ms = atoi(optarg_);
258 break;
259 case 'w':
260 video_out_save = std::string(optarg_);
261 break;
262 case 'v':
263 verbose = true;
264 break;
265 case 'y':
266 step_by_step = true;
267 break;
268 case 'h':
269 usage(argv[0], nullptr, video_in_ipath, video_in_ppath, video_in_first, video_in_last, video_in_step, me_range, me_sample_step, me_threshold, sleep_ms);
270 return false;
271
272 default:
273 usage(argv[0], optarg_, video_in_ipath, video_in_ppath, video_in_first, video_in_last, video_in_step, me_range, me_sample_step, me_threshold, sleep_ms);
274 return false;
275 }
276 }
277
278 if ((c == 1) || (c == -1)) {
279 // standalone param or error
280 usage(argv[0], nullptr, video_in_ipath, video_in_ppath, video_in_first, video_in_last, video_in_step, me_range, me_sample_step, me_threshold, sleep_ms);
281 std::cerr << "ERROR: " << std::endl;
282 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
283 return false;
284 }
285
286 return true;
287}
288
289int main(int argc, const char **argv)
290{
291#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)
292 std::string env_ipath;
293 std::string opt_ipath;
294 std::string ipath;
295 std::string opt_ppath;
296 std::string videoname;
297 int opt_first = 1;
298 int opt_last = 30;
299 int opt_step = 1;
300 int opt_me_range = 30;
301 int opt_me_sample_step = 5;
302 int opt_me_threshold = 20; // Value in [0 ; 255]
303 bool opt_click_allowed = true;
304 bool opt_display = true;
305 bool opt_display_scale_auto = false;
306 bool opt_verbose = false;
307 std::string opt_save;
308 bool opt_step_by_step = false;
309 unsigned int opt_sleep_ms = 0;
310 unsigned int thickness = 1;
311
313 vpDisplay *display = nullptr;
315
316#if defined(VISP_HAVE_DATASET)
317#if VISP_HAVE_DATASET_VERSION >= 0x030600
318 std::string ext("png");
319#else
320 std::string ext("pgm");
321#endif
322#else
323 // We suppose that the user will download a recent dataset
324 std::string ext("png");
325#endif
326
327 try {
328 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
329 // environment variable value
331
332 // Set the default input path
333 if (!env_ipath.empty())
334 ipath = env_ipath;
335
336 // Read the command line options
337 if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_first, opt_last, opt_step, opt_click_allowed,
338 opt_display, opt_display_scale_auto, opt_save,
339 opt_me_range, opt_me_sample_step, opt_me_threshold, opt_step_by_step, opt_sleep_ms, opt_verbose) == false) {
340 return EXIT_FAILURE;
341 }
342
343 // Get the option values
344 if (!opt_ipath.empty()) {
345 ipath = opt_ipath;
346 }
347
348 // Compare ipath and env_ipath. If they differ, we take into account
349 // the input path coming from the command line option
350 if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
351 if (ipath != env_ipath) {
352 std::cout << std::endl << "WARNING: " << std::endl;
353 std::cout << " Since -i <visp image path=" << ipath << "> "
354 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
355 << " we skip the environment variable." << std::endl;
356 }
357 }
358
359 // Test if an input path is set
360 if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty()) {
361 usage(argv[0], nullptr, ipath, opt_ppath, opt_first, opt_last, opt_step, opt_me_range, opt_me_sample_step, opt_me_threshold, opt_sleep_ms);
362 std::cerr << std::endl << "ERROR:" << std::endl;
363 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
364 << " environment variable to specify the location of the " << std::endl
365 << " image path where test images are located." << std::endl
366 << " Use -p <personal image path> option if you want to " << std::endl
367 << " use personal images." << std::endl
368 << std::endl;
369
370 return EXIT_FAILURE;
371 }
372
373 // Create output folder if needed
374 if (!opt_save.empty()) {
375 std::string parent = vpIoTools::getParent(opt_save);
376 if (!parent.empty()) {
377 std::cout << "Create output directory: " << parent << std::endl;
379 }
380 thickness += 1;
381 }
382
383 if (opt_ppath.empty()) {
384 // Set the path location of the image sequence
385 videoname = vpIoTools::createFilePath(ipath, "line/image.%04d." + ext);
386 g.setFileName(videoname);
387 }
388 else {
389 g.setFileName(opt_ppath);
390 }
391
392 if (opt_first > 0) {
393 g.setFirstFrameIndex(opt_first);
394 }
395 if (opt_last > 0) {
396 g.setLastFrameIndex(opt_last);
397 }
398 g.setFrameStep(opt_step);
399 g.open(I);
400
401 if (opt_display) {
402 // We open a window using either X11, GTK, GDI or OpenCV
404 if (opt_display_scale_auto) {
405 display->setDownScalingFactor(vpDisplay::SCALE_AUTO);
406 }
407 std::stringstream ss;
408 if (g.isVideoFormat()) {
409 ss << "Init tracker image " << g.getFrameIndex();
410 }
411 else {
412 std::string image_name = vpIoTools::getName(vpIoTools::formatString(g.getFrameName(), g.getFrameIndex()));
413 ss << "Init tracker image " << image_name;
414 }
415 // Display size is automatically defined by the image (I) size
416 display->init(I, 10, 10, ss.str());
417 // Display the image
418 // The image class has a member that specify a pointer toward
419 // the display that has been initialized in the display declaration
420 // therefore is is no longer necessary to make a reference to the
421 // display variable.
424 }
425
426 vpVideoWriter *writer = nullptr;
428 if (!opt_save.empty()) {
429 writer = new vpVideoWriter();
430 writer->setFileName(opt_save);
431 writer->open(O);
432 }
433
434 vpMeLine me_line;
435
436 vpMe me;
437 if (opt_me_range > 0) {
438 me.setRange(opt_me_range);
439 }
440 if (opt_me_sample_step > 0) {
441 me.setSampleStep(opt_me_sample_step);
442 }
443 if (opt_me_threshold > 0) {
445 me.setThreshold(opt_me_threshold);
446 }
447
448 me_line.setMe(&me);
450
451 std::cout << "Input video settings" << std::endl;
452 std::cout << " Name : " << g.getFrameName() << std::endl;
453 std::cout << " First image : " << g.getFirstFrameIndex() << std::endl;
454 std::cout << " Last image : " << g.getLastFrameIndex() << std::endl;
455 std::cout << " Step : " << g.getFrameStep() << std::endl;
456 std::cout << " Image size : " << I.getWidth() << " x " << I.getHeight() << std::endl;
457
458 std::cout << "Moving-edges settings" << std::endl;
459 std::cout << " Sample step : " << me_line.getMe()->getSampleStep() << std::endl;
460 std::cout << " Range : " << me_line.getMe()->getRange() << std::endl;
461 std::cout << " Threshold type: " << (me_line.getMe()->getLikelihoodThresholdType() == vpMe::NORMALIZED_THRESHOLD ? "normalized" : "old threshold (to be avoided)") << std::endl;
462 std::cout << " Threshold : " << me_line.getMe()->getThreshold() << std::endl;
463
464 if (!opt_save.empty()) {
465 std::cout << "Create video with tracking results" << std::endl;
466 std::cout << " Name : " << opt_save << std::endl;
467 }
468
469 if (opt_display && opt_click_allowed) {
470 me_line.initTracking(I);
471 }
472 else {
473 vpImagePoint ip1, ip2;
474 ip1.set_i(96);
475 ip1.set_j(191);
476 ip2.set_i(122);
477 ip2.set_j(211);
478 me_line.initTracking(I, ip1, ip2);
479 }
480 me_line.track(I);
481
482 if (opt_display) {
483 me_line.display(I, vpColor::green);
485 }
486 if (opt_display && opt_click_allowed) {
487 std::cout << "A click to continue..." << std::endl;
489 }
490
491 vpFeatureLine fe_line;
492
494
495 bool quit = false;
496 while (!g.end() && !quit) {
497 // Read the image
498 g.acquire(I);
499 std::stringstream ss;
500 if (g.isVideoFormat()) {
501 ss << "Image " << g.getFrameIndex();
502 }
503 else {
504 std::string image_name = vpIoTools::getName(g.getFrameName());
505 ss << "Image " << image_name;
506 }
507
508 if (opt_verbose) {
509 std::cout << "-- " << ss.str() << std::endl;
510 }
511 if (opt_display) {
512 // Display the image
514 vpDisplay::setTitle(I, ss.str());
515 if (opt_click_allowed) {
516 vpDisplay::displayText(I, 20, I.getWidth() - 150, std::string("Mode: ") + (opt_step_by_step ? std::string("step-by-step") : std::string("continuous")), vpColor::red);
517 vpDisplay::displayText(I, 40, I.getWidth() - 150, ss.str(), vpColor::red);
518 vpDisplay::displayText(I, 20, 10, "Right click to exit", vpColor::red);
519 vpDisplay::displayText(I, 40, 10, "Middle click to change mode", vpColor::red);
520 if (opt_step_by_step) {
521 vpDisplay::displayText(I, 60, 10, "Left click to process next image", vpColor::red);
522 }
523 }
524 }
525
526 me_line.track(I);
527
528 vpFeatureBuilder::create(fe_line, cam, me_line);
529
530 if (opt_verbose) {
531 std::cout << "me_line: rho " << me_line.getRho() << " theta (deg) " << vpMath::deg(me_line.getTheta()) << std::endl;
532 std::cout << "fe_line: rho " << fe_line.getRho() << " theta (deg) " << vpMath::deg(fe_line.getTheta()) << std::endl;
533 }
534
535 if (opt_display) {
536 me_line.display(I, vpColor::green, thickness);
538 if (opt_click_allowed) {
540 if (vpDisplay::getClick(I, button, opt_step_by_step)) {
541 if (button == vpMouseButton::button3) {
542 quit = true;
543 }
544 else if (button == vpMouseButton::button2) {
545 if (opt_step_by_step) {
546 opt_step_by_step = false;
547 }
548 else {
549 opt_step_by_step = true;
550 }
551 }
552 }
553 }
554 }
555 if (!opt_save.empty()) {
557 writer->saveFrame(O);
558 }
559
560 if (opt_sleep_ms) {
561 vpTime::sleepMs(opt_sleep_ms);
562 }
563 }
564 if (opt_display && opt_click_allowed && !quit) {
566 }
567 if (writer) {
568 delete writer;
569 }
570 if (display) {
571 delete display;
572 }
573 return EXIT_SUCCESS;
574 }
575 catch (const vpException &e) {
576 std::cout << "Catch an exception: " << e << std::endl;
577 if (opt_display && opt_click_allowed) {
579 }
580 return EXIT_FAILURE;
581 }
582#else
583 (void)argc;
584 (void)argv;
585 std::cout << "Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
586#endif
587}
588
589#else
590#include <iostream>
591
592int main()
593{
594 std::cout << "visp_me module or X11, GTK, GDI or OpenCV display functionalities are required..." << std::endl;
595 return EXIT_SUCCESS;
596}
597
598#endif
Generic class defining intrinsic camera parameters.
static const vpColor red
Definition vpColor.h:198
static const vpColor green
Definition vpColor.h:201
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 getImage(const vpImage< unsigned char > &Is, vpImage< vpRGBa > &Id)
static void setTitle(const vpImage< unsigned char > &I, const std::string &windowtitle)
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 create(vpFeaturePoint &s, const vpCameraParameters &cam, const vpDot &d)
Class that defines a 2D line visual feature which is composed by two parameters that are and ,...
double getTheta() const
double getRho() const
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
void set_j(double jj)
void set_i(double ii)
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)
static void makeDirectory(const std::string &dirname)
static std::string getParent(const std::string &pathname)
static std::string getName(const std::string &pathname)
static double deg(double rad)
Definition vpMath.h:119
Class that tracks in an image a line moving edges.
Definition vpMeLine.h:157
double getRho() const
Definition vpMeLine.h:236
void display(const vpImage< unsigned char > &I, const vpColor &color, unsigned int thickness=1)
Definition vpMeLine.cpp:177
double getTheta() const
Definition vpMeLine.h:266
void track(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:607
void initTracking(const vpImage< unsigned char > &I)
Definition vpMeLine.cpp:187
@ RANGE_RESULT
Definition vpMeSite.h:85
void setDisplay(vpMeSite::vpMeSiteDisplayType select)
void setMe(vpMe *me)
vpMe * getMe()
Definition vpMe.h:143
void setRange(const unsigned int &range)
Definition vpMe.h:438
void setLikelihoodThresholdType(const vpLikelihoodThresholdType likelihood_threshold_type)
Definition vpMe.h:531
void setThreshold(const double &threshold)
Definition vpMe.h:489
void setSampleStep(const double &sample_step)
Definition vpMe.h:445
double getThreshold() const
Definition vpMe.h:306
double getSampleStep() const
Definition vpMe.h:290
unsigned int getRange() const
Definition vpMe.h:283
@ NORMALIZED_THRESHOLD
Definition vpMe.h:154
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...
bool isVideoFormat() const
void setLastFrameIndex(const long last_frame)
long getLastFrameIndex()
void open(vpImage< vpRGBa > &I) VP_OVERRIDE
void setFileName(const std::string &filename)
void setFirstFrameIndex(const long first_frame)
long getFirstFrameIndex()
void setFrameStep(const long frame_step)
long getFrameStep() const
std::string getFrameName() const
long getFrameIndex() const
void acquire(vpImage< vpRGBa > &I) VP_OVERRIDE
Class that enables to write easily a video file or a sequence of images.
void saveFrame(vpImage< vpRGBa > &I)
void setFileName(const std::string &filename)
void open(vpImage< vpRGBa > &I)
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.
VISP_EXPORT void sleepMs(double t)