Visual Servoing Platform  version 3.5.1 under development (2023-05-30)

Tracking of an ellipse using vpMe.

* ViSP, open source Visual Servoing Platform software.
* Copyright (C) 2005 - 2019 by Inria. All rights reserved.
* This software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* See the file LICENSE.txt at the root directory of this source
* distribution for additional information about the GNU GPL.
* For using ViSP with software that can not be combined with the GNU
* GPL, please contact Inria about acquiring a ViSP Professional
* Edition License.
* See for more information.
* This software was developed at:
* Inria Rennes - Bretagne Atlantique
* Campus Universitaire de Beaulieu
* 35042 Rennes Cedex
* France
* If you have questions regarding the use of this file, please contact
* Inria at
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* Description:
* Tracking of an ellipse.
#include <visp3/core/vpConfig.h>
#include <visp3/core/vpDebug.h>
#include <iomanip>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#if defined(VISP_HAVE_MODULE_ME) && \
(defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
#include <visp3/core/vpColor.h>
#include <visp3/core/vpImage.h>
#include <visp3/core/vpImagePoint.h>
#include <visp3/core/vpIoTools.h>
#include <visp3/gui/vpDisplayGDI.h>
#include <visp3/gui/vpDisplayGTK.h>
#include <visp3/gui/vpDisplayOpenCV.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/io/vpParseArgv.h>
#include <visp3/io/vpVideoReader.h>
#include <visp3/io/vpVideoWriter.h>
#include <visp3/me/vpMeEllipse.h>
// List of allowed command line options
#define GETOPTARGS "Aacdf:hi:l:p:r:s:S:t:vw:"
void usage(const char *name, const char *badparam, const std::string &video_in_ipath, const std::string &video_in_ppath,
unsigned video_in_first, int video_in_last, int video_in_step, int me_range, int me_sample_step, int me_threshold)
std::string ext("png");
std::string ext("pgm");
fprintf(stdout, "\n\
Example of ellipse/circle or arc of ellipse/circle tracking using vpMeEllipse.\n\
%s [-i <visp dataset directory>] [-p <personal image path>]\n\
[-f <video first image>] [-l <video last image>] [-s <video step>]\n\
[-r <moving-edge range] [-t <moving-edge threshold] [-S <moving-edge sample step>]\n\
[-w <output images sequence name>] \n\
[-c] [-d] [-a] [-A] [-v] [-h]\n",
fprintf(stdout, "\n\
OPTIONS: Default\n\
-i <visp dataset directory> %s\n\
Set visp dataset directory location.\n\
From this directory read images \n\
Setting the VISP_INPUT_IMAGE_PATH environment\n\
variable produces the same behaviour than using\n\
this option.\n\
-p <personal image path> %s\n\
Specify a personal sequence containing images \n\
to process.\n\
The format is selected by analyzing \n\
the filename extension.\n\
Example : \"C:/Temp/ViSP-images/ellipse-1/image.%%04d.%s\"\n\
%%04d is for the image numbering.\n\
-f <video first image> %d\n\
First image number to process.\n\
Set -1 to process the first image of the sequence.\n\
-l <video last image> %d\n\
Last image number to process. \n\
Set -1 to process images until the last image\n\
of the sequence.\n\
-s <video step> %d\n\
Step between two images.\n\
-r <moving-edge range> %d\n\
Moving-edge range.\n\
Increase value to consider large displacement. \n\
When set to -1, use default value. \n\
-S <moving-edge sample step> %d\n\
Moving-edge sample step.\n\
Distance between two moving-edges samples in degrees. \n\
When set to -1, use default value. \n\
-t <moving-edge threshold> %d\n\
Moving-edge threshold. \n\
When the contrast is high between the two sides of the\n\
ellipse (for example white/black or black/white) a\n\
threshold of 1500 is sufficient. On the other hand, when\n\
the contrast is less strong, it is necessary to increase\n\
this threshold according to the images until 20000.\n\
When set to -1, use default value. \n\
Disable the mouse click. Useful to automate the \n\
execution of this program without human intervention.\n\
-d \n\
Turn off the display.\n\
-a \n\
Enable arc of ellipse tracking.\n\
-b \n\
Enable circle tracking.\n\
-w <output images sequence name> \n\
Save images with tracking results in overlay.\n\
Example: \"result/I%%04d.png\" \n\
-A \n\
When display is activated using -d option, enable\n\
windows auto scaling to fit the screen size. \n\
Enable verbosity.\n\
Print the help.\n",
video_in_ipath.c_str(), ext.c_str(), video_in_ppath.c_str(), ext.c_str(), video_in_first, video_in_last,
video_in_step, me_range, me_sample_step, me_threshold);
if (badparam)
fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
bool getOptions(int argc, const char **argv, std::string &video_in_ipath, std::string &video_in_ppath,
int &video_in_first, int &video_in_last, int &video_in_step,
bool &click_allowed, bool &display, bool &display_scale_auto, bool &track_arc,
std::string &video_out_save, int &me_range, int &me_sample_step, int &me_threshold, bool &verbose)
const char *optarg_;
int c;
while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
switch (c) {
case 'A':
display_scale_auto = true;
case 'a':
track_arc = true;
case 'c':
click_allowed = false;
case 'd':
display = false;
case 'f':
video_in_first = atoi(optarg_);
case 'i':
video_in_ipath = std::string(optarg_);
case 'l':
video_in_last = atoi(optarg_);
case 'p':
video_in_ppath = std::string(optarg_);
case 'r':
me_range = atoi(optarg_);
case 's':
video_in_step = atoi(optarg_);
case 'S':
me_sample_step = atoi(optarg_);
case 't':
me_threshold = atoi(optarg_);
case 'w':
video_out_save = std::string(optarg_);
case 'v':
verbose = true;
case 'h':
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);
return false;
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);
return false;
if ((c == 1) || (c == -1)) {
// standalone param or error
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);
std::cerr << "ERROR: " << std::endl;
std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
return false;
return true;
int main(int argc, const char **argv)
#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)
std::string env_ipath;
std::string opt_ipath;
std::string ipath;
std::string opt_ppath;
std::string videoname;
int opt_first = -1;
int opt_last = -1;
int opt_step = 1;
int opt_me_range = 30;
int opt_me_sample_step = 5;
int opt_me_threshold = -1;
bool opt_click_allowed = true;
bool opt_display = true;
bool opt_display_scale_auto = false;
bool opt_track_arc = false;
bool opt_verbose = false;
std::string opt_save;
unsigned int thickness = 1;
// Declare an image, this is a gray level image (unsigned char)
// it size is not defined yet, it will be defined when the image is
// read on the disk
vpDisplay *display = NULL;
try {
// Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
// environment variable value
// Set the default input path
if (!env_ipath.empty())
ipath = env_ipath;
// Read the command line options
if (getOptions(argc, argv, opt_ipath, opt_ppath, opt_first, opt_last, opt_step, opt_click_allowed,
opt_display, opt_display_scale_auto, opt_track_arc, opt_save,
opt_me_range, opt_me_sample_step, opt_me_threshold, opt_verbose) == false) {
// Get the option values
if (!opt_ipath.empty())
ipath = opt_ipath;
// Compare ipath and env_ipath. If they differ, we take into account
// the input path comming from the command line option
if (!opt_ipath.empty() && !env_ipath.empty() && opt_ppath.empty()) {
if (ipath != env_ipath) {
std::cout << std::endl << "WARNING: " << std::endl;
std::cout << " Since -i <visp image path=" << ipath << "> "
<< " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
<< " we skip the environment variable." << std::endl;
// Test if an input path is set
if (opt_ipath.empty() && env_ipath.empty() && opt_ppath.empty()) {
usage(argv[0], NULL, ipath, opt_ppath, opt_first, opt_last, opt_step, opt_me_range, opt_me_sample_step, opt_me_threshold);
std::cerr << std::endl << "ERROR:" << std::endl;
std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
<< " environment variable to specify the location of the " << std::endl
<< " image path where test images are located." << std::endl
<< " Use -p <personal image path> option if you want to " << std::endl
<< " use personal images." << std::endl
<< std::endl;
// Create output folder if needed
if (! opt_save.empty()) {
std::string parent = vpIoTools::getParent(opt_save);
if (! parent.empty()) {
std::cout << "Create output directory: " << parent << std::endl;
thickness += 1;
if (opt_ppath.empty()) {
// Set the path location of the image sequence
videoname = vpIoTools::createFilePath(ipath, "ellipse-1/image.%04d.png");
videoname = vpIoTools::createFilePath(ipath, "ellipse-1/image.%04d.pgm");
else {
if (opt_first > 0) {
if (opt_last > 0) {
if (opt_display) {
// We open a window using either X11, GTK or GDI.
#if defined VISP_HAVE_X11
display = new vpDisplayX;
#elif defined VISP_HAVE_GTK
display = new vpDisplayGTK;
#elif defined VISP_HAVE_GDI
display = new vpDisplayGDI;
#elif defined VISP_HAVE_OPENCV
display = new vpDisplayOpenCV;
if (opt_display_scale_auto) {
// Display size is automatically defined by the image (I) size
display->init(I, 10, 10, "Current image");
// Display the image
// The image class has a member that specify a pointer toward
// the display that has been initialized in the display declaration
// therefore is is no longer necessary to make a reference to the
// display variable.
vpVideoWriter *writer = NULL;
if (! opt_save.empty()) {
writer = new vpVideoWriter();
vpMeEllipse me_ellipse;
vpMe me;
if (opt_me_range > 0) {
if (opt_me_sample_step > 0) {
if (opt_me_threshold > 0) {
std::cout << "Video settings" << std::endl;
std::cout << " Name : " << g.getFrameName() << std::endl;
std::cout << " First image: " << g.getFirstFrameIndex() << std::endl;
std::cout << " Last image : " << g.getLastFrameIndex() << std::endl;
std::cout << " Step : " << g.getFrameStep() << std::endl;
std::cout << " Image size : " << I.getWidth() << " x " << I.getHeight() << std::endl;
std::cout << "Moving-edges settings" << std::endl;
std::cout << " Sample step: " << me_ellipse.getMe()->getSampleStep() << std::endl;
std::cout << " Range : " << me_ellipse.getMe()->getRange() << std::endl;
std::cout << " Threshold : " << me_ellipse.getMe()->getThreshold() << std::endl;
if (opt_click_allowed) {
me_ellipse.initTracking(I, opt_track_arc);
else {
// Create a list of clockwise points to automate the test
std::vector<vpImagePoint> ip;
ip.push_back(vpImagePoint(195, 329));
ip.push_back(vpImagePoint(243, 164));
ip.push_back(vpImagePoint(201, 36));
ip.push_back(vpImagePoint(83, 126));
ip.push_back(vpImagePoint(33, 276));
me_ellipse.initTracking(I, ip, opt_track_arc);
if (opt_display) {
me_ellipse.display(I, vpColor::green, thickness);
if (opt_display && opt_click_allowed) {
std::cout << "A click to continue..." << std::endl;
bool quit = false;
while (!g.end() && !quit) {
// Read the image
std::stringstream ss;
ss << "Process image " << g.getFrameIndex();
if (opt_verbose) {
std::cout << "-- " << ss.str() << std::endl;
if (opt_display) {
// Display the image
vpDisplay::displayText(I, 20, 10, ss.str(), vpColor::red);
if (opt_click_allowed) {
vpDisplay::displayText(I, 40, 10, "Click to exit...", vpColor::red);
if (opt_display) {
me_ellipse.display(I, vpColor::green, thickness);
if (! opt_save.empty()) {
if (opt_display && opt_click_allowed) {
if (vpDisplay::getClick(I, false)) {
quit = true;
if (opt_display && opt_click_allowed && !quit) {
if (writer) {
delete writer;
if (display) {
delete display;
} catch (const vpException &e) {
std::cout << "Catch an exception: " << e << std::endl;
if (opt_display && opt_click_allowed) {
std::cout << "Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
#include <iostream>
int main()
std::cout << "visp_me module or X11, GTK, GDI or OpenCV display "
"functionalities are required..."
<< std::endl;
static const vpColor red
Definition: vpColor.h:217
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
Class that defines generic functionnalities for display.
Definition: vpDisplay.h:178
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)
Definition: vpDisplay.cpp:144
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.h:183
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
error that can be emited by ViSP classes.
Definition: vpException.h:72
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:89
unsigned int getWidth() const
Definition: vpImage.h:247
unsigned int getHeight() const
Definition: vpImage.h:189
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1399
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1764
static void makeDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:585
static std::string getParent(const std::string &pathname)
Definition: vpIoTools.cpp:1651
Class that tracks an ellipse using moving edges.
Definition: vpMeEllipse.h:95
void initTracking(const vpImage< unsigned char > &I, bool trackArc=false)
void track(const vpImage< unsigned char > &I)
void display(const vpImage< unsigned char > &I, const vpColor &color, unsigned int thickness=1)
Definition: vpMeSite.h:69
vpMe * getMe()
Definition: vpMeTracker.h:116
void setDisplay(vpMeSite::vpMeSiteDisplayType select)
Definition: vpMeTracker.h:148
void setMe(vpMe *p_me)
Definition: vpMeTracker.h:169
Definition: vpMe.h:119
void setSampleStep(const double &s)
Definition: vpMe.h:337
void setRange(const unsigned int &r)
Definition: vpMe.h:330
double getThreshold() const
Definition: vpMe.h:252
double getSampleStep() const
Definition: vpMe.h:344
unsigned int getRange() const
Definition: vpMe.h:237
void setThreshold(const double &t)
Definition: vpMe.h:364
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
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)