Visual Servoing Platform version 3.5.0
trackDot2WithAutoDetection.cpp
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 * Test auto detection of dots.
33 *
34 * Authors:
35 * Fabien Spindler
36 *
37 *****************************************************************************/
50#include <visp3/core/vpConfig.h>
51#include <visp3/core/vpDebug.h>
52
53#include <iomanip>
54#include <sstream>
55#include <stdio.h>
56#include <stdlib.h>
57
58#if defined(VISP_HAVE_MODULE_BLOB) && \
59 (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
60
61#include <visp3/blob/vpDot2.h>
62#include <visp3/core/vpImage.h>
63#include <visp3/core/vpImagePoint.h>
64#include <visp3/core/vpIoTools.h>
65#include <visp3/gui/vpDisplayGDI.h>
66#include <visp3/gui/vpDisplayGTK.h>
67#include <visp3/gui/vpDisplayOpenCV.h>
68#include <visp3/gui/vpDisplayX.h>
69#include <visp3/io/vpImageIo.h>
70#include <visp3/io/vpParseArgv.h>
71
72// List of allowed command line options
73#define GETOPTARGS "cdi:p:f:n:s:S:G:E:h"
74
75void usage(const char *name, const char *badparam, std::string ipath, std::string ppath, unsigned first,
76 unsigned nimages, unsigned step, double sizePrecision, double grayLevelPrecision,
77 double ellipsoidShapePrecision);
78bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first, unsigned &nimages,
79 unsigned &step, double &sizePrecision, double &grayLevelPrecision, double &ellipsoidShapePrecision,
80 bool &click_allowed, bool &display);
81
99void usage(const char *name, const char *badparam, std::string ipath, std::string ppath, unsigned first,
100 unsigned nimages, unsigned step, double sizePrecision, double grayLevelPrecision,
101 double ellipsoidShapePrecision)
102{
103 fprintf(stdout, "\n\
104Test auto detection of dots using vpDot2.\n\
105 \n\
106SYNOPSIS\n\
107 %s [-i <input image path>] [-p <personal image path>]\n\
108 [-f <first image>] [-n <number of images>] [-s <step>] \n\
109 [-S <size precision>] [-G <gray level precision>]\n\
110 [-E <ellipsoid shape precision>] [-c] [-d] [-h]\n", name);
111
112 fprintf(stdout, "\n\
113OPTIONS: Default\n\
114 -i <input image path> %s\n\
115 Set image input path.\n\
116 From this path read images \n\
117 \"mire-2/image.%%04d.pgm\"\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 The following image file formats PNM (PGM P5, PPM P6)\n\
127 are supported. The format is selected by analysing \n\
128 the filename extension.\n\
129 Example : \"/Temp/ViSP-images/cube/image.%%04d.pgm\"\n\
130 %%04d is for the image numbering.\n\
131 \n\
132 -f <first image> %u\n\
133 First image number of the sequence.\n\
134 \n\
135 -n <number of images> %u\n\
136 Number of images to load from the sequence.\n\
137 \n\
138 -s <step> %u\n\
139 Step between two images.\n\
140 \n\
141 -S <size precision> %f\n\
142 Precision of the size of the dot. \n\
143 It is a double precision float witch value is in ]0,1].\n\
144 1 means full precision, the sizes (width, heigth, surface) \n\
145 of the dots must the same, whereas values close to 0 \n\
146 show a very bad precision.\n\
147\n\
148 -G <gray level precision> %f\n\
149 Precision of the gray level of the dot. \n\
150 It is a double precision float witch value is in ]0,1].\n\
151 1 means full precision, the gray level must the same in \n\
152 the wall dot, whereas values close to 0 \n\
153 show a very bad precision.\n\
154\n\
155 -E <ellipsoid shape precision> %f\n\
156 Precision of the ellipsoid shape of the dot. \n\
157 It is a double precision float witch value is in [0,1].\n\
158 1 means full precision, the shape should be a perfect ellipsoid,\n\
159 whereas values close to 0 show a very bad precision.\n\
160 0 means the shape of dots is not tested \n\
161\n", ipath.c_str(), ppath.c_str(), first, nimages, step, sizePrecision, grayLevelPrecision,
162 ellipsoidShapePrecision);
163
164 fprintf(stdout, "\
165 -c\n\
166 Disable the mouse click. Useful to automaze the \n\
167 execution of this program without humain intervention.\n\
168 \n\
169 -d \n\
170 Turn off the display.\n\
171 \n\
172 -h\n\
173 Print the help.\n");
174
175 if (badparam)
176 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
177}
198bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first, unsigned &nimages,
199 unsigned &step, double &sizePrecision, double &grayLevelPrecision, double &ellipsoidShapePrecision,
200 bool &click_allowed, bool &display)
201{
202 const char *optarg_;
203 int c;
204 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
205
206 switch (c) {
207 case 'c':
208 click_allowed = false;
209 break;
210 case 'd':
211 display = false;
212 break;
213 case 'i':
214 ipath = optarg_;
215 break;
216 case 'p':
217 ppath = optarg_;
218 break;
219 case 'f':
220 first = (unsigned)atoi(optarg_);
221 break;
222 case 'n':
223 nimages = (unsigned)atoi(optarg_);
224 break;
225 case 's':
226 step = (unsigned)atoi(optarg_);
227 break;
228 case 'S':
229 sizePrecision = atof(optarg_);
230 break;
231 case 'G':
232 grayLevelPrecision = atof(optarg_);
233 break;
234 case 'E':
235 ellipsoidShapePrecision = atof(optarg_);
236 break;
237 case 'h':
238 usage(argv[0], NULL, ipath, ppath, first, nimages, step, sizePrecision, grayLevelPrecision,
239 ellipsoidShapePrecision);
240 return false;
241 break;
242
243 default:
244 usage(argv[0], optarg_, ipath, ppath, first, nimages, step, sizePrecision, grayLevelPrecision,
245 ellipsoidShapePrecision);
246 return false;
247 break;
248 }
249 }
250
251 if ((c == 1) || (c == -1)) {
252 // standalone param or error
253 usage(argv[0], NULL, ipath, ppath, first, nimages, step, sizePrecision, grayLevelPrecision,
254 ellipsoidShapePrecision);
255 std::cerr << "ERROR: " << std::endl;
256 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
257 return false;
258 }
259
260 return true;
261}
262
263int main(int argc, const char **argv)
264{
265 try {
266 std::string env_ipath;
267 std::string opt_ipath;
268 std::string ipath;
269 std::string opt_ppath;
270 std::string dirname;
271 std::string filename;
272 unsigned opt_first = 1;
273 unsigned opt_nimages = 10;
274 unsigned opt_step = 1;
275 double opt_sizePrecision = 0.65;
276 double opt_grayLevelPrecision = 0.85;
277 double opt_ellipsoidShapePrecision = 0.8;
278 bool opt_click_allowed = true;
279 bool opt_display = true;
280
281 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
282 // environment variable value
284
285 // Set the default input path
286 if (!env_ipath.empty())
287 ipath = env_ipath;
288
289 // Read the command line options
290 if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_first, opt_nimages, opt_step, opt_sizePrecision,
291 opt_grayLevelPrecision, opt_ellipsoidShapePrecision, opt_click_allowed, opt_display) == false) {
292 exit(-1);
293 }
294
295 // Get the option values
296 if (!opt_ipath.empty())
297 ipath = opt_ipath;
298
299 // Compare ipath and env_ipath. If they differ, we take into account
300 // the input path comming from the command line option
301 if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
302 if (ipath != env_ipath) {
303 std::cout << std::endl << "WARNING: " << std::endl;
304 std::cout << " Since -i <visp image path=" << ipath << "> "
305 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
306 << " we skip the environment variable." << std::endl;
307 }
308 }
309
310 // Test if an input path is set
311 if (opt_ipath.empty() && env_ipath.empty()) {
312 usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_nimages, opt_step, opt_sizePrecision,
313 opt_grayLevelPrecision, opt_ellipsoidShapePrecision);
314 std::cerr << std::endl << "ERROR:" << std::endl;
315 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
316 << " environment variable to specify the location of the " << std::endl
317 << " image path where test images are located." << std::endl
318 << std::endl
319 << " Use -p <personal image path> option if you want to " << std::endl
320 << " use personal images." << std::endl;
321 exit(-1);
322 }
323
324 // Declare an image, this is a gray level image (unsigned char)
325 // it size is not defined yet, it will be defined when the image will
326 // read on the disk
328 std::ostringstream s;
329 char cfilename[FILENAME_MAX];
330 unsigned iter = opt_first; // Image number
331
332 if (opt_ppath.empty()) {
333
334 // Warning :
335 // the image sequence is not provided with the ViSP package
336 // therefore the program will return you an error :
337 // !! vpImageIoPnm.cpp: readPGM(#210) :couldn't read file
338 // ViSP-images/cube/image.0001.pgm
339 // !! vpDotExample.cpp: main(#95) :Error while reading the image
340 // terminate called after throwing an instance of 'vpImageException'
341 //
342 // The sequence is available on the visp www site
343 // https://visp.inria.fr/download/
344 // in the download section. It is named "ViSP-images.tar.gz"
345
346 // Set the path location of the image sequence
347 dirname = vpIoTools::createFilePath(ipath, "mire-2");
348
349 // Build the name of the image file
350
351 s.setf(std::ios::right, std::ios::adjustfield);
352 s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
353 filename = vpIoTools::createFilePath(dirname, s.str());
354 } else {
355
356 sprintf(cfilename, opt_ppath.c_str(), iter);
357 filename = cfilename;
358 }
359 // Read the PGM image named "filename" on the disk, and put the
360 // bitmap into the image structure I. I is initialized to the
361 // correct size
362 //
363 // exception readPGM may throw various exception if, for example,
364 // the file does not exist, or if the memory cannot be allocated
365 try {
366 vpCTRACE << "Load: " << filename << std::endl;
367
368 vpImageIo::read(I, filename);
369 } catch (...) {
370 // an exception is throwned if an exception from readPGM has been
371 // catched here this will result in the end of the program Note that
372 // another error message has been printed from readPGM to give more
373 // information about the error
374 std::cerr << std::endl << "ERROR:" << std::endl;
375 std::cerr << " Cannot read " << filename << std::endl;
376 std::cerr << " Check your -i " << ipath << " option " << std::endl
377 << " or your -p " << opt_ppath << " option " << std::endl
378 << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
379 exit(-1);
380 }
381
382// We open a window using either GTK, X11 or GDI.
383#if defined VISP_HAVE_GTK
384 vpDisplayGTK display;
385#elif defined VISP_HAVE_X11
386 vpDisplayX display;
387#elif defined VISP_HAVE_GDI
388 vpDisplayGDI display;
389#elif defined VISP_HAVE_OPENCV
390 vpDisplayOpenCV display;
391#endif
392
393 if (opt_display) {
394 // Display size is automatically defined by the image (I) size
395 display.init(I, 100, 100, "Display...");
396 // Display the image
397 // The image class has a member that specify a pointer toward
398 // the display that has been initialized in the display declaration
399 // therefore is is no longuer necessary to make a reference to the
400 // display variable.
403 }
404
405 // Dot declaration
406 vpDot2 d;
407
408 d.setGraphics(true);
409 if (opt_click_allowed & opt_display) {
410 d.setGrayLevelPrecision(opt_grayLevelPrecision);
411
412 std::cout << "Please click on a dot to initialize detection" << std::endl;
413
414 d.initTracking(I);
415 if (opt_display) {
416 vpImagePoint cog;
417 cog = d.getCog();
420 }
421 d.setSizePrecision(opt_sizePrecision);
422 d.setEllipsoidShapePrecision(opt_ellipsoidShapePrecision);
423 printf("Dot characteristics: \n");
424 printf(" width : %lf\n", d.getWidth());
425 printf(" height: %lf\n", d.getHeight());
426 printf(" area: %lf\n", d.getArea());
427 printf(" gray level min: %u\n", d.getGrayLevelMin());
428 printf(" gray level max: %u\n", d.getGrayLevelMax());
429 printf(" grayLevelPrecision: %lf\n", d.getGrayLevelPrecision());
430 printf(" sizePrecision: %lf\n", d.getSizePrecision());
431 printf(" ellipsoidShapePrecision: %lf\n", d.getEllipsoidShapePrecision());
432 } else {
433 // Set dot characteristics for the auto detection
434 d.setGraphics(true);
435 d.setWidth(15.0);
436 d.setHeight(12.0);
437 d.setArea(124);
438 d.setGrayLevelMin(164);
439 d.setGrayLevelMax(255);
440 d.setGrayLevelPrecision(opt_grayLevelPrecision);
441 d.setSizePrecision(opt_sizePrecision);
442 d.setEllipsoidShapePrecision(opt_ellipsoidShapePrecision);
443 }
444
445 while (iter < opt_first + opt_nimages * opt_step) {
446 // set the new image name
447
448 if (opt_ppath.empty()) {
449
450 s.str("");
451 s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
452 filename = vpIoTools::createFilePath(dirname, s.str());
453 } else {
454 sprintf(cfilename, opt_ppath.c_str(), iter);
455 filename = cfilename;
456 }
457 // read the image
458 vpImageIo::read(I, filename);
459
460 if (opt_display) {
461 // Display the image
463 }
464
465 std::cout << "Search dots in image" << filename << std::endl;
466 std::list<vpDot2> list_d;
467 d.searchDotsInArea(I, 0, 0, I.getWidth(), I.getHeight(), list_d);
468
469 if (list_d.empty()) {
470 std::cout << "Dot auto detection did not work." << std::endl;
471 return (-1);
472 } else {
473 std::cout << std::endl << list_d.size() << " dots are detected" << std::endl;
474
475 if (opt_display) {
476 int i = 0;
477 // Parse all founded dots for display
478 for (std::list<vpDot2>::const_iterator it = list_d.begin(); it != list_d.end(); ++it) {
479 vpImagePoint cog = (*it).getCog();
480
481 std::cout << "Dot " << i++ << " : " << cog.get_u() << " " << cog.get_v() << std::endl;
482
484 }
486 }
487 }
488
489 // If click is allowed, wait for a mouse click to launch the next
490 // iteration
491 if (opt_display && opt_click_allowed) {
492 std::cout << "\nA click to continue..." << std::endl;
493 // Wait for a blocking mouse click
495 }
496
497 iter += opt_step;
498 }
499 if (opt_display && opt_click_allowed) {
500 std::cout << "\nA click to exit..." << std::endl;
501 // Wait for a blocking mouse click
503 }
504
505 return EXIT_SUCCESS;
506 } catch (const vpException &e) {
507 std::cout << "Catch an exception: " << e << std::endl;
508 return EXIT_FAILURE;
509 }
510}
511#else
512#include <iostream>
513
514int main()
515{
516 std::cout << "visp_me module or X11, GTK, GDI or OpenCV display "
517 "functionalities are required..."
518 << std::endl;
519 return EXIT_SUCCESS;
520}
521
522#endif
static const vpColor blue
Definition: vpColor.h:223
static const vpColor green
Definition: vpColor.h:220
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:129
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:135
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 displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
unsigned int getHeight() const
Definition: vpDisplay.h:240
static void flush(const vpImage< unsigned char > &I)
unsigned int getWidth() const
Definition: vpDisplay.h:245
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:127
error that can be emited by ViSP classes.
Definition: vpException.h:72
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:149
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
double get_u() const
Definition: vpImagePoint.h:262
double get_v() const
Definition: vpImagePoint.h:273
unsigned int getWidth() const
Definition: vpImage.h:246
unsigned int getHeight() const
Definition: vpImage.h:188
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1365
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1670
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
#define vpCTRACE
Definition: vpDebug.h:338