37#include <visp3/core/vpImage.h>
38#include <visp3/core/vpImageTools.h>
39#include <visp3/core/vpCameraParameters.h>
40#include <visp3/core/vpTime.h>
41#include <visp3/core/vpHomogeneousMatrix.h>
42#include <visp3/core/vpMath.h>
43#include <visp3/core/vpUniRand.h>
44#include <visp3/core/vpIoTools.h>
45#include <visp3/robot/vpSimulatorCamera.h>
46#include <visp3/robot/vpImageSimulator.h>
47#include <visp3/io/vpImageIo.h>
48#include <visp3/io/vpParseArgv.h>
49#include <visp3/gui/vpDisplayFactory.h>
50#include <visp3/visual_features/vpFeatureLuminanceMapping.h>
54#ifdef ENABLE_VISP_NAMESPACE
60#define GETOPTARGS "cdi:n:p:m:k:hl:"
62void usage(
const char *name,
const char *badparam,
const std::string &ipath,
int niter,
const std::string &method,
unsigned numDbImages,
const unsigned numComponents,
const double lambda);
63bool getOptions(
int argc,
const char **argv, std::string &ipath,
bool &click_allowed,
bool &display,
int &niter, std::string &method,
unsigned &numDbImages,
unsigned &numComponents,
double &lambda);
75void usage(
const char *name,
const char *badparam,
const std::string &ipath,
int niter,
const std::string &method,
unsigned numDbImages,
const unsigned numComponents,
const double lambda)
78Visual servoing with compressed photometric features.\n\
79Use either PCA or DCT representations\n\
83 %s [-i <input image path>] [-m pca|dct] [-p <v>] [-c] [-d] [-n <number of iterations>] [-h]\n",
88 -i <input image path> %s\n\
89 Set image input path.\n\
90 From this path read \"doisneau/doisneau.jpg\"\n\
92 Setting the VISP_INPUT_IMAGE_PATH environment\n\
93 variable produces the same behaviour than using\n\
97 Method to use: either 'PCA' or 'DCT'\n\
98 PCA first requires learning a projection from a base of images. see the -p option.\n\
101 Number of visual servoing features (i.e., PCA or DCT components)\n\
105 Number of images to use to compute PCA. If method is DCT, this option is ignored.\n\
109 Disable the mouse click. Useful to automate the \n\
110 execution of this program without human intervention.\n\
113 Turn off the display.\n\
116 Number of visual servoing iterations.\n\
119 Number of visual servoing iterations.\n\
123 ipath.c_str(), method.c_str(), numComponents, numDbImages, niter, lambda);
126 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
142bool getOptions(
int argc,
const char **argv, std::string &ipath,
bool &click_allowed,
bool &display,
143 int &niter, std::string &method,
unsigned &numDbImages,
unsigned &numComponents,
double &lambda)
151 click_allowed =
false;
160 method = std::string(optarg_);
163 numDbImages = atoi(optarg_);
166 numComponents = atoi(optarg_);
169 niter = atoi(optarg_);
172 lambda = atof(optarg_);
175 usage(argv[0],
nullptr, ipath, niter, method, numDbImages, numComponents, lambda);
179 usage(argv[0], optarg_, ipath, niter, method, numDbImages, numComponents, lambda);
184 if ((c == 1) || (c == -1)) {
186 usage(argv[0],
nullptr, ipath, niter, method, numDbImages, numComponents, lambda);
187 std::cerr <<
"ERROR: " << std::endl;
188 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
195int main(
int argc,
const char **argv)
197#if (defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)) && (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
198#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
204 std::string env_ipath;
205 std::string opt_ipath;
208 bool opt_click_allowed =
true;
209 bool opt_display =
true;
211 std::string opt_method =
"dct";
212 unsigned opt_numDbImages = 2000;
213 unsigned opt_numComponents = 32;
214 double opt_lambda = 5.0;
217 double lambdaGN = opt_lambda;
221 const double Z = 0.8;
222 const unsigned ih = 240;
223 const unsigned iw = 320;
224 const double scenew = 0.6;
225 const double sceneh = 0.42;
232 if (!env_ipath.empty())
236 if (getOptions(argc, argv, opt_ipath, opt_click_allowed, opt_display, opt_niter, opt_method,
237 opt_numDbImages, opt_numComponents, opt_lambda) ==
false) {
242 if (!opt_ipath.empty())
247 if (!opt_ipath.empty() && !env_ipath.empty()) {
248 if (ipath != env_ipath) {
249 std::cout << std::endl <<
"WARNING: " << std::endl;
250 std::cout <<
" Since -i <visp image path=" << ipath <<
"> "
251 <<
" is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
252 <<
" we skip the environment variable." << std::endl;
257 if (opt_ipath.empty() && env_ipath.empty()) {
258 usage(argv[0],
nullptr, ipath, opt_niter, opt_method, opt_numDbImages, opt_numComponents, opt_lambda);
259 std::cerr << std::endl <<
"ERROR:" << std::endl;
260 std::cerr <<
" Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
261 <<
" environment variable to specify the location of the " << std::endl
262 <<
" image path where test images are located." << std::endl
272 for (
int i = 0;
i < 4;
i++)
275 X[0][0] = -(scenew / 2.0);
276 X[0][1] = -(sceneh / 2.0);
280 X[1][0] = (scenew / 2.0);
281 X[1][1] = -(sceneh / 2.0);
285 X[2][0] = (scenew / 2.0);
286 X[2][1] = (sceneh / 2.0);
290 X[3][0] = -(scenew / 2.0);
291 X[3][1] = (sceneh / 2.0);
298 sim.
init(Itexture, X);
311 std::shared_ptr<vpLuminanceMapping> sMapping =
nullptr;
312 std::shared_ptr<vpLuminanceMapping> sdMapping =
nullptr;
315 if (opt_method ==
"pca") {
317 std::cout <<
"Building image database for PCA computation with " << opt_numDbImages <<
" images" << std::endl;
318#if defined(VISP_HAVE_DISPLAY)
319#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
325 d->init(I, 0, 0,
"Image database (subsample)");
328 std::vector<vpImage<unsigned char>> images(opt_numDbImages);
329 for (
unsigned i = 0;
i < opt_numDbImages; ++
i) {
331 const double noiseDiv = 16.0;
332 positionNoise[0] = random.uniform(-scenew / noiseDiv, scenew / noiseDiv);
333 positionNoise[1] = random.uniform(-sceneh / noiseDiv, sceneh / noiseDiv);
334 positionNoise[2] = random.uniform(0.0, Z / noiseDiv);
335 const double noiseDivTo = 16.0;
336 to[0] = random.uniform(-scenew / noiseDivTo, scenew / noiseDivTo);
337 to[1] = random.uniform(-sceneh / noiseDivTo, sceneh / noiseDivTo);
344 if (i % 20 == 0 && opt_display) {
349 std::cout <<
"Computing PCA, this may take some time!" << std::endl;
353 sMapping = std::shared_ptr<vpLuminanceMapping>(
new vpLuminancePCA(pca));
354 sdMapping = std::shared_ptr<vpLuminanceMapping>(
new vpLuminancePCA(pca));
356#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
362 else if (opt_method ==
"dct") {
363 sMapping = std::shared_ptr<vpLuminanceMapping>(
new vpLuminanceDCT(opt_numComponents));
364 sdMapping = std::shared_ptr<vpLuminanceMapping>(
new vpLuminanceDCT(opt_numComponents));
375#if defined(VISP_HAVE_DISPLAY)
376#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
383 d->init(I, 20, 10,
"Current image");
386 if (opt_click_allowed) {
387 std::cout <<
"Click in the image to continue..." << std::endl;
408#if defined(VISP_HAVE_DISPLAY)
413 if (opt_display && opt_click_allowed) {
414 std::cout <<
"Click in the image to continue..." << std::endl;
425#if defined(VISP_HAVE_DISPLAY)
426#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
434 d1->init(Idiff, 40 +
static_cast<int>(I.getWidth()), 10,
"photometric visual servoing : s-s* ");
435 d2->init(Irec, 40 +
static_cast<int>(I.getWidth()) * 2, 10,
"Reconstructed image");
446 wMc = wMo *
cMo.inverse();
447 robot.setPosition(wMc);
456 luminanceI.
init(I.getHeight(), I.getWidth(), Z);
460 sI.getMapping()->inverse(sI.get_s(), Irec);
464 luminanceId.
init(I.getHeight(), I.getWidth(), Z);
473 int iterGN = opt_niter / 8;
474 double normError = 0;
486 std::cout <<
"Starting VS loop" << std::endl;
488 std::cout <<
"--------------------------------------------" <<
iter++ << std::endl;
497 sI.getMapping()->inverse(sI.get_s(), Irec);
501 opt_lambda = lambdaGN;
504 sI.error(sId, error);
507 for (
unsigned int i = 0;
i < n;
i++) {
508 diagHs[
i][
i] = Hs[
i][
i];
510 H = ((mu * diagHs) + Hs).inverseByLU();
512 v = -opt_lambda * H * L.
t() *
error;
513 normError =
error.sumSquare();
515 std::cout <<
" |e| = " << normError << std::endl;
516 std::cout <<
" |v| = " << sqrt(
v.sumSquare()) << std::endl;
518#if defined(VISP_HAVE_DISPLAY)
531 wMc = robot.getPosition();
533 }
while (normError > 200 && iter < opt_niter);
536 std::cout <<
"Time to convergence: " << chrono.
getDurationMs() <<
" ms" << std::endl;
541#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
551 if (normError > 200) {
557 std::cout <<
"Catch an exception: " <<
e << std::endl;
558#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
575 std::cout <<
"Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
Generic class defining intrinsic camera parameters.
void start(bool reset=true)
Implementation of column vector and the associated operations.
static const vpColor black
Class that defines generic functionalities for display.
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void flush(const vpImage< unsigned char > &I)
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.
Class to combine luminance features (photometric servoing).
Class that defines the image luminance visual feature.
void init(unsigned int _nbr, unsigned int _nbc, double _Z)
static const int DEFAULT_BORDER
void setCameraParameters(const vpCameraParameters &_cam)
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix inverse() const
vpTranslationVector getTranslationVector() const
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Class which enables to project an image in the 3D space and get the view of a virtual camera.
void getImage(vpImage< unsigned char > &I, const vpCameraParameters &cam)
void init(const vpImage< unsigned char > &I, vpColVector *X)
void setCleanPreviousImage(const bool &clean, const vpColor &color=vpColor::white)
void setInterpolationType(const vpInterpolationType interplt)
void setCameraPosition(const vpHomogeneousMatrix &cMt)
Definition of the vpImage class member functions.
Implementation of marchand20a.
Implementation of marchand19a.
static vpLuminancePCA learn(const std::vector< std::string > &imageFiles, const unsigned int projectionSize, const unsigned int imageBorder=0)
Compute a new Principal Component Analysis on set of images, stored on disk.
vpColVector getExplainedVariance() const
Get the values of explained variance by each of the eigen vectors.
static double rad(double deg)
static vpHomogeneousMatrix lookAt(const vpColVector &from, const vpColVector &to, vpColVector tmp)
Implementation of a matrix and operations on matrices.
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
virtual void setSamplingTime(const double &delta_t)
@ STATE_VELOCITY_CONTROL
Initialize the velocity controller.
Implementation of a rotation matrix and operations on such kind of matrices.
Class that defines the simplest robot: a free flying camera.
Class for generating random numbers with uniform probability density.
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.