Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
trackMeEllipse.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2023 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 https://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 an ellipse.
33 *
34*****************************************************************************/
35
47#include <visp3/core/vpConfig.h>
48#include <visp3/core/vpDebug.h>
49
50#include <iomanip>
51#include <sstream>
52#include <stdio.h>
53#include <stdlib.h>
54
55#if defined(VISP_HAVE_MODULE_ME) && \
56 (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
57
58#include <visp3/core/vpColor.h>
59#include <visp3/core/vpImage.h>
60#include <visp3/core/vpImagePoint.h>
61#include <visp3/core/vpIoTools.h>
62#include <visp3/gui/vpDisplayGDI.h>
63#include <visp3/gui/vpDisplayGTK.h>
64#include <visp3/gui/vpDisplayOpenCV.h>
65#include <visp3/gui/vpDisplayX.h>
66#include <visp3/io/vpParseArgv.h>
67#include <visp3/io/vpVideoReader.h>
68#include <visp3/io/vpVideoWriter.h>
69#include <visp3/me/vpMeEllipse.h>
70
71// List of allowed command line options
72#define GETOPTARGS "Aabcdf:hi:l:p:r:s:S:t:vw:"
73
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, int me_threshold)
90{
91#if VISP_HAVE_DATASET_VERSION >= 0x030600
92 std::string ext("png");
93#else
94 std::string ext("pgm");
95#endif
96 fprintf(stdout, "\n\
97Example of ellipse/circle or arc of ellipse/circle tracking using vpMeEllipse.\n\
98\n\
99SYNOPSIS\n\
100 %s [-i <visp dataset directory>] [-p <personal image path>]\n\
101 [-f <video first image>] [-l <video last image>] [-s <video step>]\n\
102 [-r <moving-edge range] [-t <moving-edge threshold] [-S <moving-edge sample step>]\n\
103 [-w <output images sequence name>] \n\
104 [-c] [-d] [-a] [-A] [-b] [-v] [-h]\n",
105 name);
106
107 fprintf(stdout, "\n\
108OPTIONS: Default\n\
109 -i <visp dataset directory> %s\n\
110 Set visp dataset directory location.\n\
111 From this directory read images \n\
112 \"ellipse-1/image.%%04d.%s\"\n\
113 Setting the VISP_INPUT_IMAGE_PATH environment\n\
114 variable produces the same behaviour than using\n\
115 this option.\n\
116 \n\
117 -p <personal image path> %s\n\
118 Specify a personal sequence containing images \n\
119 to process.\n\
120 The format is selected by analyzing \n\
121 the filename extension.\n\
122 Example : \"C:/Temp/ViSP-images/ellipse-1/image.%%04d.%s\"\n\
123 %%04d is for the image numbering.\n\
124 \n\
125 -f <video first image> %d\n\
126 First image number to process.\n\
127 Set -1 to process the first image of the sequence.\n\
128 \n\
129 -l <video last image> %d\n\
130 Last image number to process. \n\
131 Set -1 to process images until the last image\n\
132 of the sequence.\n\
133 \n\
134 -s <video step> %d\n\
135 Step between two images.\n\
136 \n\
137 -r <moving-edge range> %d\n\
138 Moving-edge range.\n\
139 Increase value to consider large displacement. \n\
140 When set to -1, use default value. \n\
141 \n\
142 -S <moving-edge sample step> %d\n\
143 Moving-edge sample step.\n\
144 Distance between two moving-edges samples in degrees. \n\
145 When set to -1, use default value. \n\
146 \n\
147 -t <moving-edge threshold> %d\n\
148 Moving-edge threshold corresponding to the minimum \n\
149 contrast to consider. Value in range [0 ; 255] \n\
150 When set to -1, use default value. \n\
151 \n\
152 -c\n\
153 Disable the mouse click. Useful to automate the \n\
154 execution of this program without human intervention.\n\
155 \n\
156 -d \n\
157 Turn off the display.\n\
158 \n\
159 -a \n\
160 Enable arc of ellipse tracking.\n\
161 \n\
162 -b \n\
163 Enable circle tracking.\n\
164 \n\
165 -w <output images sequence name> \n\
166 Save images with tracking results in overlay.\n\
167 Example: \"result/I%%04d.png\" \n\
168 \n\
169 -A \n\
170 When display is activated using -d option, enable\n\
171 windows auto scaling to fit the screen size. \n\
172 \n\
173 -v\n\
174 Enable verbosity.\n\
175 \n\
176 -h\n\
177 Print the help.\n",
178 video_in_ipath.c_str(), ext.c_str(), video_in_ppath.c_str(), ext.c_str(), video_in_first, video_in_last,
179 video_in_step, me_range, me_sample_step, me_threshold);
180
181 if (badparam)
182 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
183}
184
210bool getOptions(int argc, const char **argv, std::string &video_in_ipath, std::string &video_in_ppath,
211 int &video_in_first, int &video_in_last, int &video_in_step,
212 bool &click_allowed, bool &display, bool &display_scale_auto, bool &track_circle, bool &track_arc,
213 std::string &video_out_save, int &me_range, int &me_sample_step, int &me_threshold, bool &verbose)
214{
215 const char *optarg_;
216 int c;
217 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
218
219 switch (c) {
220 case 'A':
221 display_scale_auto = true;
222 break;
223 case 'a':
224 track_arc = true;
225 break;
226 case 'b':
227 track_circle = true;
228 break;
229 case 'c':
230 click_allowed = false;
231 break;
232 case 'd':
233 display = false;
234 break;
235 case 'f':
236 video_in_first = atoi(optarg_);
237 break;
238 case 'i':
239 video_in_ipath = std::string(optarg_);
240 break;
241 case 'l':
242 video_in_last = atoi(optarg_);
243 break;
244 case 'p':
245 video_in_ppath = std::string(optarg_);
246 break;
247 case 'r':
248 me_range = atoi(optarg_);
249 break;
250 case 's':
251 video_in_step = atoi(optarg_);
252 break;
253 case 'S':
254 me_sample_step = atoi(optarg_);
255 break;
256 case 't':
257 me_threshold = 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 'h':
266 usage(argv[0], NULL, video_in_ipath, video_in_ppath, video_in_first, video_in_last, video_in_step, me_range, me_sample_step, me_threshold);
267 return false;
268 break;
269
270 default:
271 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);
272 return false;
273 break;
274 }
275 }
276
277 if ((c == 1) || (c == -1)) {
278 // standalone param or error
279 usage(argv[0], NULL, video_in_ipath, video_in_ppath, video_in_first, video_in_last, video_in_step, me_range, me_sample_step, me_threshold);
280 std::cerr << "ERROR: " << std::endl;
281 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
282 return false;
283 }
284
285 return true;
286}
287
288int main(int argc, const char **argv)
289{
290#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)
291 std::string env_ipath;
292 std::string opt_ipath;
293 std::string ipath;
294 std::string opt_ppath;
295 std::string videoname;
296 int opt_first = -1;
297 int opt_last = -1;
298 int opt_step = 1;
299 int opt_me_range = 30;
300 int opt_me_sample_step = 5;
301 int opt_me_threshold = 20; // Value in [0 ; 255]
302 bool opt_click_allowed = true;
303 bool opt_display = true;
304 bool opt_display_scale_auto = false;
305 bool opt_track_circle = false;
306 bool opt_track_arc = false;
307 bool opt_verbose = false;
308 std::string opt_save;
309 unsigned int thickness = 1;
310
311 // Declare an image, this is a gray level image (unsigned char)
312 // it size is not defined yet, it will be defined when the image is
313 // read on the disk
315
316 vpDisplay *display = NULL;
317
318 try {
319 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
320 // environment variable value
322
323 // Set the default input path
324 if (!env_ipath.empty())
325 ipath = env_ipath;
326
327 // Read the command line options
328 if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_first, opt_last, opt_step, opt_click_allowed,
329 opt_display, opt_display_scale_auto, opt_track_circle, opt_track_arc, opt_save,
330 opt_me_range, opt_me_sample_step, opt_me_threshold, opt_verbose) == false) {
331 return EXIT_FAILURE;
332 }
333
334 // Get the option values
335 if (!opt_ipath.empty())
336 ipath = opt_ipath;
337
338 // Compare ipath and env_ipath. If they differ, we take into account
339 // the input path comming from the command line option
340 if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
341 if (ipath != env_ipath) {
342 std::cout << std::endl << "WARNING: " << std::endl;
343 std::cout << " Since -i <visp image path=" << ipath << "> "
344 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
345 << " we skip the environment variable." << std::endl;
346 }
347 }
348
349 // Test if an input path is set
350 if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty()) {
351 usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_last, opt_step, opt_me_range, opt_me_sample_step, opt_me_threshold);
352 std::cerr << std::endl << "ERROR:" << std::endl;
353 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
354 << " environment variable to specify the location of the " << std::endl
355 << " image path where test images are located." << std::endl
356 << " Use -p <personal image path> option if you want to " << std::endl
357 << " use personal images." << std::endl
358 << std::endl;
359
360 return EXIT_FAILURE;
361 }
362
363 // Create output folder if needed
364 if (!opt_save.empty()) {
365 std::string parent = vpIoTools::getParent(opt_save);
366 if (!parent.empty()) {
367 std::cout << "Create output directory: " << parent << std::endl;
369 }
370 thickness += 1;
371 }
372
374 if (opt_ppath.empty()) {
375 // Set the path location of the image sequence
376#if VISP_HAVE_DATASET_VERSION >= 0x030600
377 videoname = vpIoTools::createFilePath(ipath, "ellipse-1/image.%04d.png");
378#else
379 videoname = vpIoTools::createFilePath(ipath, "ellipse-1/image.%04d.pgm");
380#endif
381 g.setFileName(videoname);
382 }
383 else {
384 g.setFileName(opt_ppath);
385 }
386
387 if (opt_first > 0) {
388 g.setFirstFrameIndex(opt_first);
389 }
390 if (opt_last > 0) {
391 g.setLastFrameIndex(opt_last);
392 }
393 g.setFrameStep(opt_step);
394 g.open(I);
395
396 if (opt_display) {
397 // We open a window using either X11, GTK or GDI.
398#if defined(VISP_HAVE_X11)
399 display = new vpDisplayX;
400#elif defined(VISP_HAVE_GTK)
401 display = new vpDisplayGTK;
402#elif defined(VISP_HAVE_GDI)
403 display = new vpDisplayGDI;
404#elif defined(HAVE_OPENCV_HIGHGUI)
405 display = new vpDisplayOpenCV;
406#endif
407 if (opt_display_scale_auto) {
408 display->setDownScalingFactor(vpDisplay::SCALE_AUTO);
409 }
410 // Display size is automatically defined by the image (I) size
411 display->init(I, 10, 10, "Current image");
412 // Display the image
413 // The image class has a member that specify a pointer toward
414 // the display that has been initialized in the display declaration
415 // therefore is is no longer necessary to make a reference to the
416 // display variable.
419 }
420
421 vpVideoWriter *writer = NULL;
423 if (!opt_save.empty()) {
424 writer = new vpVideoWriter();
425 writer->setFileName(opt_save);
426 writer->open(O);
427 }
428 vpMeEllipse me_ellipse;
429
430 vpMe me;
431 if (opt_me_range > 0) {
432 me.setRange(opt_me_range);
433 }
434 if (opt_me_sample_step > 0) {
435 me.setSampleStep(opt_me_sample_step);
436 }
437 if (opt_me_threshold > 0) {
439 me.setThreshold(opt_me_threshold);
440 }
441
442 me_ellipse.setMe(&me);
444
445 std::cout << "Video settings" << std::endl;
446 std::cout << " Name : " << g.getFrameName() << std::endl;
447 std::cout << " First image: " << g.getFirstFrameIndex() << std::endl;
448 std::cout << " Last image : " << g.getLastFrameIndex() << std::endl;
449 std::cout << " Step : " << g.getFrameStep() << std::endl;
450 std::cout << " Image size : " << I.getWidth() << " x " << I.getHeight() << std::endl;
451
452 std::cout << "Moving-edges settings" << std::endl;
453 std::cout << " Sample step : " << me_ellipse.getMe()->getSampleStep() << std::endl;
454 std::cout << " Range : " << me_ellipse.getMe()->getRange() << std::endl;
455 std::cout << " Threshold type: " << (me_ellipse.getMe()->getLikelihoodThresholdType() == vpMe::NORMALIZED_THRESHOLD ? "normalized" : "old threshold (to be avoided)") << std::endl;
456 std::cout << " Threshold : " << me_ellipse.getMe()->getThreshold() << std::endl;
457
458 if (opt_click_allowed) {
459 me_ellipse.initTracking(I, opt_track_circle, opt_track_arc);
460 }
461 else {
462 // Create a list of clockwise points to automate the test
463 std::vector<vpImagePoint> ip;
464 ip.push_back(vpImagePoint(195, 329));
465 ip.push_back(vpImagePoint(243, 164));
466 ip.push_back(vpImagePoint(201, 36));
467 ip.push_back(vpImagePoint(83, 126));
468 ip.push_back(vpImagePoint(33, 276));
469
470 me_ellipse.initTracking(I, ip, opt_track_circle, opt_track_arc);
471 }
472 if (opt_display) {
473 me_ellipse.display(I, vpColor::green, thickness);
474 }
475
476 if (opt_display && opt_click_allowed) {
477 std::cout << "A click to continue..." << std::endl;
479 }
480 bool quit = false;
481
482 while (!g.end() && !quit) {
483 // Read the image
484 g.acquire(I);
485 std::stringstream ss;
486 ss << "Process image " << g.getFrameIndex();
487 if (opt_verbose) {
488 std::cout << "-- " << ss.str() << std::endl;
489 }
490 if (opt_display) {
491 // Display the image
493 vpDisplay::displayText(I, 20, 10, ss.str(), vpColor::red);
494 if (opt_click_allowed) {
495 vpDisplay::displayText(I, 40, 10, "Click to exit...", vpColor::red);
496 }
497 }
498 me_ellipse.track(I);
499
500 if (opt_display) {
501 me_ellipse.display(I, vpColor::green, thickness);
503 }
504 if (!opt_save.empty()) {
506 writer->saveFrame(O);
507 }
508 if (opt_display && opt_click_allowed) {
509 if (vpDisplay::getClick(I, false)) {
510 quit = true;
511 }
512 }
513 }
514
515 if (opt_display && opt_click_allowed && !quit) {
517 }
518
519 if (writer) {
520 delete writer;
521 }
522 if (display) {
523 delete display;
524 }
525 return EXIT_SUCCESS;
526 }
527 catch (const vpException &e) {
528 std::cout << "Catch an exception: " << e << std::endl;
529 if (opt_display && opt_click_allowed) {
531 }
532 return EXIT_FAILURE;
533 }
534#else
535 (void)argc;
536 (void)argv;
537 std::cout << "Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
538#endif
539}
540#else
541#include <iostream>
542
543int main()
544{
545 std::cout << "visp_me module or X11, GTK, GDI or OpenCV display "
546 "functionalities are required..."
547 << std::endl;
548 return EXIT_SUCCESS;
549}
550
551#endif
static const vpColor red
Definition vpColor.h:211
static const vpColor green
Definition vpColor.h:214
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:132
Class that defines generic functionalities for display.
Definition vpDisplay.h:173
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 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:59
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition of the vpImage class member functions.
Definition vpImage.h:135
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:184
static std::string getViSPImagesDataPath()
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)
Class that tracks an ellipse using moving edges.
Definition vpMeEllipse.h:90
void display(const vpImage< unsigned char > &I, const vpColor &col, unsigned int thickness=1)
void initTracking(const vpImage< unsigned char > &I, bool trackCircle=false, bool trackArc=false)
void track(const vpImage< unsigned char > &I)
@ RANGE_RESULT
Definition vpMeSite.h:75
void setDisplay(vpMeSite::vpMeSiteDisplayType select)
vpMe * getMe()
void setMe(vpMe *p_me)
Definition vpMe.h:122
void setSampleStep(const double &s)
Definition vpMe.h:390
void setRange(const unsigned int &r)
Definition vpMe.h:383
vpLikelihoodThresholdType getLikelihoodThresholdType() const
Definition vpMe.h:297
void setLikelihoodThresholdType(const vpLikelihoodThresholdType likelihood_threshold_type)
Definition vpMe.h:445
double getThreshold() const
Definition vpMe.h:288
double getSampleStep() const
Definition vpMe.h:397
unsigned int getRange() const
Definition vpMe.h:273
@ NORMALIZED_THRESHOLD
Easy-to-use normalized likelihood threshold corresponding to the minimal luminance contrast to consid...
Definition vpMe.h:132
void setThreshold(const double &t)
Definition vpMe.h:435
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 acquire(vpImage< vpRGBa > &I)
void setLastFrameIndex(const long last_frame)
long getLastFrameIndex()
void open(vpImage< vpRGBa > &I)
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
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)