Visual Servoing Platform version 3.5.0
trackDot.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 * Example of dot tracking.
33 *
34 * Authors:
35 * Eric Marchand
36 * Fabien Spindler
37 *
38 *****************************************************************************/
39
52#include <visp3/core/vpConfig.h>
53#include <visp3/core/vpDebug.h>
54
55#include <iomanip>
56#include <sstream>
57#include <stdio.h>
58#include <stdlib.h>
59
60#if defined(VISP_HAVE_MODULE_BLOB) && \
61 (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
62
63#include <visp3/blob/vpDot.h>
64#include <visp3/core/vpImage.h>
65#include <visp3/core/vpImagePoint.h>
66#include <visp3/core/vpIoTools.h>
67#include <visp3/gui/vpDisplayGDI.h>
68#include <visp3/gui/vpDisplayGTK.h>
69#include <visp3/gui/vpDisplayOpenCV.h>
70#include <visp3/gui/vpDisplayX.h>
71#include <visp3/io/vpImageIo.h>
72#include <visp3/io/vpParseArgv.h>
73
74// List of allowed command line options
75#define GETOPTARGS "cdf:i:n:p:s:h"
76
77void usage(const char *name, const char *badparam, std::string ipath, std::string ppath, unsigned first,
78 unsigned nimages, unsigned step);
79bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first, unsigned &nimages,
80 unsigned &step, bool &click_allowed, bool &display);
81
95void usage(const char *name, const char *badparam, std::string ipath, std::string ppath, unsigned first,
96 unsigned nimages, unsigned step)
97{
98 fprintf(stdout, "\n\
99Test dot tracking.\n\
100\n\
101SYNOPSIS\n\
102 %s [-i <test image path>] [-p <personal image path>]\n\
103 [-f <first image>] [-n <number of images>] [-s <step>]\n\
104 [-c] [-d] [-h]\n", name);
105
106 fprintf(stdout, "\n\
107OPTIONS: Default\n\
108 -i <input image path> %s\n\
109 Set image input path.\n\
110 From this path read images \n\
111 \"mire-2/image.%%04d.pgm\". These \n\
112 images come from ViSP-images-x.y.z.tar.gz available \n\
113 on the ViSP website.\n\
114 Setting the VISP_INPUT_IMAGE_PATH environment\n\
115 variable produces the same behaviour than using\n\
116 this option.\n\
117 \n\
118 -p <personal image path> %s\n\
119 Specify a personal sequence containing images \n\
120 to process.\n\
121 By image sequence, we mean one file per image.\n\
122 The following image file formats PNM (PGM P5, PPM P6)\n\
123 are supported. The format is selected by analysing \n\
124 the filename extension.\n\
125 Example : \"C:/Temp/ViSP-images/cube/image.%%04d.pgm\"\n\
126 %%04d is for the image numbering.\n\
127 \n\
128 -f <first image> %u\n\
129 First image number of the sequence.\n\
130 \n\
131 -n <number of images> %u\n\
132 Number of images to load from the sequence.\n\
133 \n\
134 -s <step> %u\n\
135 Step between two images.\n\
136\n\
137 -c\n\
138 Disable the mouse click. Useful to automaze the \n\
139 execution of this program without humain intervention.\n\
140\n\
141 -d \n\
142 Turn off the display.\n\
143\n\
144 -h\n\
145 Print the help.\n", ipath.c_str(), ppath.c_str(), first, nimages, step);
146
147 if (badparam)
148 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
149}
167bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath, unsigned &first, unsigned &nimages,
168 unsigned &step, bool &click_allowed, bool &display)
169{
170 const char *optarg_;
171 int c;
172 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
173
174 switch (c) {
175 case 'c':
176 click_allowed = false;
177 break;
178 case 'd':
179 display = false;
180 break;
181 case 'i':
182 ipath = optarg_;
183 break;
184 case 'p':
185 ppath = optarg_;
186 break;
187 case 'f':
188 first = (unsigned)atoi(optarg_);
189 break;
190 case 'n':
191 nimages = (unsigned)atoi(optarg_);
192 break;
193 case 's':
194 step = (unsigned)atoi(optarg_);
195 break;
196 case 'h':
197 usage(argv[0], NULL, ipath, ppath, first, nimages, step);
198 return false;
199 break;
200
201 default:
202 usage(argv[0], optarg_, ipath, ppath, first, nimages, step);
203 return false;
204 break;
205 }
206 }
207
208 if ((c == 1) || (c == -1)) {
209 // standalone param or error
210 usage(argv[0], NULL, ipath, ppath, first, nimages, step);
211 std::cerr << "ERROR: " << std::endl;
212 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
213 return false;
214 }
215
216 return true;
217}
218
219int main(int argc, const char **argv)
220{
221 try {
222 std::string env_ipath;
223 std::string opt_ipath;
224 std::string ipath;
225 std::string opt_ppath;
226 std::string dirname;
227 std::string filename;
228 unsigned opt_first = 1;
229 unsigned opt_nimages = 500;
230 unsigned opt_step = 1;
231 bool opt_click_allowed = true;
232 bool opt_display = true;
233
234 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
235 // environment variable value
237
238 // Set the default input path
239 if (!env_ipath.empty())
240 ipath = env_ipath;
241
242 // Read the command line options
243 if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_first, opt_nimages, opt_step, opt_click_allowed,
244 opt_display) == false) {
245 exit(-1);
246 }
247
248 // Get the option values
249 if (!opt_ipath.empty())
250 ipath = opt_ipath;
251
252 // Compare ipath and env_ipath. If they differ, we take into account
253 // the input path comming from the command line option
254 if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
255 if (ipath != env_ipath) {
256 std::cout << std::endl << "WARNING: " << std::endl;
257 std::cout << " Since -i <visp image path=" << ipath << "> "
258 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
259 << " we skip the environment variable." << std::endl;
260 }
261 }
262
263 // Test if an input path is set
264 if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty()) {
265 usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_nimages, opt_step);
266 std::cerr << std::endl << "ERROR:" << std::endl;
267 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
268 << " environment variable to specify the location of the " << std::endl
269 << " image path where test images are located." << std::endl
270 << " Use -p <personal image path> option if you want to " << std::endl
271 << " use personal images." << std::endl
272 << std::endl;
273
274 exit(-1);
275 }
276
277 // Declare an image, this is a gray level image (unsigned char)
278 // it size is not defined yet, it will be defined when the image will
279 // read on the disk
281
282 unsigned iter = opt_first;
283 std::ostringstream s;
284 char cfilename[FILENAME_MAX];
285
286 if (opt_ppath.empty()) {
287
288 // Warning :
289 // the image sequence is not provided with the ViSP package
290 // therefore the program will return you an error :
291 // !! vpImageIoPnm.cpp: readPGM(#210) :couldn't read file
292 // ViSP-images/mire-2/image.0001.pgm
293 // !! vpDotExample.cpp: main(#95) :Error while reading the image
294 // terminate called after throwing an instance of 'vpImageException'
295 //
296 // The sequence is available on the visp www site
297 // https://visp.inria.fr/download/
298 // in the download section. It is named "ViSP-images.tar.gz"
299
300 // Set the path location of the image sequence
301 dirname = vpIoTools::createFilePath(ipath, "mire-2");
302
303 // Build the name of the image file
304
305 s.setf(std::ios::right, std::ios::adjustfield);
306 s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
307 filename = vpIoTools::createFilePath(dirname, s.str());
308 } else {
309
310 sprintf(cfilename, opt_ppath.c_str(), iter);
311 filename = cfilename;
312 }
313
314 // Read the PGM image named "filename" on the disk, and put the
315 // bitmap into the image structure I. I is initialized to the
316 // correct size
317 //
318 // exception readPGM may throw various exception if, for example,
319 // the file does not exist, or if the memory cannot be allocated
320 try {
321 vpCTRACE << "Load: " << filename << std::endl;
322
323 vpImageIo::read(I, filename);
324 } catch (...) {
325 // an exception is throwned if an exception from readPGM has been
326 // catched here this will result in the end of the program Note that
327 // another error message has been printed from readPGM to give more
328 // information about the error
329 std::cerr << std::endl << "ERROR:" << std::endl;
330 std::cerr << " Cannot read " << filename << std::endl;
331 std::cerr << " Check your -i " << ipath << " option " << std::endl
332 << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
333 exit(-1);
334 }
335
336// We open a window using either X11, GTK or GDI.
337#if defined VISP_HAVE_X11
338 vpDisplayX display;
339#elif defined VISP_HAVE_GTK
340 vpDisplayGTK display;
341#elif defined VISP_HAVE_GDI
342 vpDisplayGDI display;
343#elif defined VISP_HAVE_OPENCV
344 vpDisplayOpenCV display;
345#endif
346
347 if (opt_display) {
348 // Display size is automatically defined by the image (I) size
349 display.init(I, 100, 100, "Display...");
350 // Display the image
351 // The image class has a member that specify a pointer toward
352 // the display that has been initialized in the display declaration
353 // therefore is is no longuer necessary to make a reference to the
354 // display variable.
357 }
358
359 // by using setGraphics, we request to see the all the pixel of the dot
360 vpDot d;
361 if (opt_display) {
362 // by using setGraphics, we request to see the all the pixel of the dot
363 // in green on the screen.
364 // It uses the overlay image plane.
365 // The default of this setting is that it is time consumming
366 d.setGraphics(true);
367 } else {
368 d.setGraphics(false);
369 }
370 // we also request to compute the dot moment m00, m10, m01, m11, m20, m02
371 d.setComputeMoments(true);
372 d.setConnexity(vpDot::CONNEXITY_8);
373
374 if (opt_display && opt_click_allowed) {
375 // tracking is initalized
376 // if no other parameters are given to the iniTracking(..) method
377 // a right mouse click on the dot is expected
378 std::cout << "Click on a white dot you want to track..." << std::endl;
379 d.initTracking(I);
380 } else {
381 // dot location can also be specified explicitely in the
382 // initTracking method : d.initTracking(I,ip) where ip is the
383 // image point from which the dot is searched
384 vpImagePoint ip;
385 ip.set_u(160);
386 ip.set_v(212);
387 d.initTracking(I, ip);
388 }
389
390 vpImagePoint cog;
391 while (iter < opt_first + opt_nimages * opt_step) {
392 // set the new image name
393 if (opt_ppath.empty()) {
394 s.str("");
395 s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
396 filename = vpIoTools::createFilePath(dirname, s.str());
397 } else {
398 sprintf(cfilename, opt_ppath.c_str(), iter);
399 filename = cfilename;
400 }
401 // read the image
402 std::cout << "read : " << filename << std::endl;
403 vpImageIo::read(I, filename);
404
405 if (opt_display) {
406 // Display the image
408 }
409 std::cout << "Tracking on image: " << filename << std::endl;
410
411 // track the dot
412 double time = vpTime::measureTimeMs();
413 d.track(I);
414
415 std::cout << "COG (" << vpTime::measureTimeMs() - time << " ms): " << std::endl;
416 cog = d.getCog();
417 std::cout << cog.get_u() << " " << cog.get_v() << std::endl;
418 std::cout << "Size:" << std::endl;
419 std::cout << " w: " << d.getWidth() << " h: " << d.getHeight() << std::endl;
420 std::cout << "Area: " << d.getArea() << std::endl;
421 std::cout << "Centered normalized moments nij:" << std::endl;
422 std::cout << " n20: " << d.get_nij()[0] << std::endl;
423 std::cout << " n11: " << d.get_nij()[1] << std::endl;
424 std::cout << " n02: " << d.get_nij()[2] << std::endl;
425
426 if (0) {
427 std::list<vpImagePoint> edges = d.getEdges();
428 std::list<vpImagePoint>::const_iterator it;
429 for (it = edges.begin(); it != edges.end(); ++it) {
431 }
432 }
433
434 if (opt_display) {
435 // display a red cross (size 10) in the image at the dot center
436 // of gravity location
438 // flush the X11 buffer
440 }
441 iter++;
442 }
443
444 if (opt_display && opt_click_allowed) {
445 std::cout << "\nA click to exit..." << std::endl;
446 // Wait for a blocking mouse click
448 }
449 return EXIT_SUCCESS;
450 } catch (const vpException &e) {
451 std::cout << "Catch an exception: " << e << std::endl;
452 return EXIT_FAILURE;
453 }
454}
455#else
456#include <iostream>
457
458int main()
459{
460 std::cout << "visp_blob module or X11, GTK, GDI or OpenCV display "
461 "functionalities are required..."
462 << std::endl;
463 return EXIT_SUCCESS;
464}
465
466#endif
static const vpColor red
Definition: vpColor.h:217
static const vpColor blue
Definition: vpColor.h:223
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)
static void displayPoint(const vpImage< unsigned char > &I, const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1)
unsigned int getWidth() const
Definition: vpDisplay.h:245
This tracker is meant to track a dot (connected pixels with same gray level) on a vpImage.
Definition: vpDot.h:116
@ CONNEXITY_8
Definition: vpDot.h:124
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
void set_u(double u)
Definition: vpImagePoint.h:225
void set_v(double v)
Definition: vpImagePoint.h:236
double get_v() const
Definition: vpImagePoint.h:273
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
VISP_EXPORT double measureTimeMs()