Visual Servoing Platform  version 3.1.0
testKeyPoint-2.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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 keypoint matching and pose estimation.
33  *
34  * Authors:
35  * Souriya Trinh
36  *
37  *****************************************************************************/
38 
39 #include <iostream>
40 
41 #include <visp3/core/vpConfig.h>
42 
43 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020301)
44 
45 #include <visp3/core/vpImage.h>
46 #include <visp3/core/vpIoTools.h>
47 #include <visp3/gui/vpDisplayGDI.h>
48 #include <visp3/gui/vpDisplayGTK.h>
49 #include <visp3/gui/vpDisplayOpenCV.h>
50 #include <visp3/gui/vpDisplayX.h>
51 #include <visp3/io/vpImageIo.h>
52 #include <visp3/io/vpParseArgv.h>
53 #include <visp3/io/vpVideoReader.h>
54 #include <visp3/mbt/vpMbEdgeTracker.h>
55 #include <visp3/vision/vpKeyPoint.h>
56 
57 // List of allowed command line options
58 #define GETOPTARGS "cdh"
59 
60 void usage(const char *name, const char *badparam);
61 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
62 
71 void usage(const char *name, const char *badparam)
72 {
73  fprintf(stdout, "\n\
74 Test keypoints matching.\n\
75 \n\
76 SYNOPSIS\n\
77  %s [-c] [-d] [-h]\n", name);
78 
79  fprintf(stdout, "\n\
80 OPTIONS: \n\
81 \n\
82  -c\n\
83  Disable the mouse click. Useful to automaze the \n\
84  execution of this program without humain intervention.\n\
85 \n\
86  -d \n\
87  Turn off the display.\n\
88 \n\
89  -h\n\
90  Print the help.\n");
91 
92  if (badparam)
93  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
94 }
95 
107 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display)
108 {
109  const char *optarg_;
110  int c;
111  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
112 
113  switch (c) {
114  case 'c':
115  click_allowed = false;
116  break;
117  case 'd':
118  display = false;
119  break;
120  case 'h':
121  usage(argv[0], NULL);
122  return false;
123  break;
124 
125  default:
126  usage(argv[0], optarg_);
127  return false;
128  break;
129  }
130  }
131 
132  if ((c == 1) || (c == -1)) {
133  // standalone param or error
134  usage(argv[0], NULL);
135  std::cerr << "ERROR: " << std::endl;
136  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
137  return false;
138  }
139 
140  return true;
141 }
142 
148 int main(int argc, const char **argv)
149 {
150  try {
151  std::string env_ipath;
152  bool opt_click_allowed = true;
153  bool opt_display = true;
154 
155  // Read the command line options
156  if (getOptions(argc, argv, opt_click_allowed, opt_display) == false) {
157  exit(-1);
158  }
159 
160  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
161  // environment variable value
162  env_ipath = vpIoTools::getViSPImagesDataPath();
163 
164  if (env_ipath.empty()) {
165  std::cerr << "Please set the VISP_INPUT_IMAGE_PATH environment "
166  "variable value."
167  << std::endl;
168  return -1;
169  }
170 
172 
173  // Set the path location of the image sequence
174  std::string dirname = vpIoTools::createFilePath(env_ipath, "mbt/cube");
175 
176  // Build the name of the image files
177  std::string filenameRef = vpIoTools::createFilePath(dirname, "image0000.pgm");
178  vpImageIo::read(I, filenameRef);
179  std::string filenameCur = vpIoTools::createFilePath(dirname, "image%04d.pgm");
180 
181 #if defined VISP_HAVE_X11
182  vpDisplayX display;
183 #elif defined VISP_HAVE_GTK
184  vpDisplayGTK display;
185 #elif defined VISP_HAVE_GDI
186  vpDisplayGDI display;
187 #else
188  vpDisplayOpenCV display;
189 #endif
190 
191  if (opt_display) {
193  display.init(I, 0, 0, "ORB keypoints matching and pose estimation");
194  }
195 
196  vpCameraParameters cam;
197  vpMbEdgeTracker tracker;
198  // Load config for tracker
199  std::string tracker_config_file = vpIoTools::createFilePath(env_ipath, "mbt/cube.xml");
200 
201 #ifdef VISP_HAVE_XML2
202  tracker.loadConfigFile(tracker_config_file);
203  tracker.getCameraParameters(cam);
204 #else
205  vpMe me;
206  me.setMaskSize(5);
207  me.setMaskNumber(180);
208  me.setRange(8);
209  me.setThreshold(10000);
210  me.setMu1(0.5);
211  me.setMu2(0.5);
212  me.setSampleStep(4);
213  me.setNbTotalSample(250);
214  tracker.setMovingEdge(me);
215  cam.initPersProjWithoutDistortion(547.7367575, 542.0744058, 338.7036994, 234.5083345);
216  tracker.setCameraParameters(cam);
217  tracker.setNearClippingDistance(0.01);
218  tracker.setFarClippingDistance(100.0);
220 #endif
221 
222  tracker.setAngleAppear(vpMath::rad(89));
223  tracker.setAngleDisappear(vpMath::rad(89));
224 
225  // Load CAO model
226  std::string cao_model_file = vpIoTools::createFilePath(env_ipath, "mbt/cube.cao");
227  tracker.loadModel(cao_model_file);
228 
229  // Initialize the pose
230  std::string init_file = vpIoTools::createFilePath(env_ipath, "mbt/cube.init");
231  if (opt_display && opt_click_allowed) {
232  tracker.initClick(I, init_file);
233  } else {
234  vpHomogeneousMatrix cMoi(0.02044769891, 0.1101505452, 0.5078963719, 2.063603907, 1.110231561, -0.4392789872);
235  tracker.initFromPose(I, cMoi);
236  }
237 
238  // Get the init pose
240  tracker.getPose(cMo);
241 
242  // Init keypoints
243  vpKeyPoint keypoints("ORB", "ORB", "BruteForce-Hamming");
244 #if (VISP_HAVE_OPENCV_VERSION >= 0x020400)
245  // Bug when using LSH index with FLANN and OpenCV 2.3.1.
246  // see http://code.opencv.org/issues/1741 (Bug #1741)
247  keypoints.setMatcher("FlannBased");
248 #if (VISP_HAVE_OPENCV_VERSION < 0x030000)
249  keypoints.setDetectorParameter("ORB", "nLevels", 1);
250 #else
251  cv::Ptr<cv::ORB> orb_detector = keypoints.getDetector("ORB").dynamicCast<cv::ORB>();
252  if (orb_detector != NULL) {
253  orb_detector->setNLevels(1);
254  }
255 #endif
256 #endif
257 
258  // Detect keypoints on the current image
259  std::vector<cv::KeyPoint> trainKeyPoints;
260  double elapsedTime;
261  keypoints.detect(I, trainKeyPoints, elapsedTime);
262 
263  // Keep only keypoints on the cube
264  std::vector<vpPolygon> polygons;
265  std::vector<std::vector<vpPoint> > roisPt;
266  std::pair<std::vector<vpPolygon>, std::vector<std::vector<vpPoint> > > pair =
267  tracker.getPolygonFaces(true); // To detect an issue with CI
268  polygons = pair.first;
269  roisPt = pair.second;
270 
271  // Compute the 3D coordinates
272  std::vector<cv::Point3f> points3f;
273  vpKeyPoint::compute3DForPointsInPolygons(cMo, cam, trainKeyPoints, polygons, roisPt, points3f);
274 
275  // Build the reference keypoints
276  keypoints.buildReference(I, trainKeyPoints, points3f, false, 1);
277 
278  // Read image 150
279  filenameRef = vpIoTools::createFilePath(dirname, "image0150.pgm");
280  vpImageIo::read(I, filenameRef);
281 
282  // Init pose at image 150
283  cMo.buildFrom(0.02651282185, -0.03713587374, 0.6873765919, 2.314744454, 0.3492296488, -0.1226054828);
284  tracker.initFromPose(I, cMo);
285 
286  // Detect keypoints on the image 150
287  keypoints.detect(I, trainKeyPoints, elapsedTime);
288 
289  // Keep only keypoints on the cube
290  pair = tracker.getPolygonFaces(true, true,
291  true); // To detect an issue with CI
292  polygons = pair.first;
293  roisPt = pair.second;
294 
295  // Compute the 3D coordinates
296  vpKeyPoint::compute3DForPointsInPolygons(cMo, cam, trainKeyPoints, polygons, roisPt, points3f);
297 
298  // Build the reference keypoints
299  keypoints.buildReference(I, trainKeyPoints, points3f, true, 2);
300 
301  // Read image 200
302  filenameRef = vpIoTools::createFilePath(dirname, "image0200.pgm");
303  vpImageIo::read(I, filenameRef);
304 
305  // Init pose at image 200
306  cMo.buildFrom(0.02965448956, -0.07283091786, 0.7253526051, 2.300529617, -0.4286674806, 0.1788761025);
307  tracker.initFromPose(I, cMo);
308 
309  // Detect keypoints on the image 200
310  keypoints.detect(I, trainKeyPoints, elapsedTime);
311 
312  // Keep only keypoints on the cube
313  pair = tracker.getPolygonFaces(false); // To detect an issue with CI
314  polygons = pair.first;
315  roisPt = pair.second;
316 
317  // Compute the 3D coordinates
318  vpKeyPoint::compute3DForPointsInPolygons(cMo, cam, trainKeyPoints, polygons, roisPt, points3f);
319 
320  // Build the reference keypoints
321  keypoints.buildReference(I, trainKeyPoints, points3f, true, 3);
322 
323  // Init reader for getting the input image sequence
324  vpVideoReader g;
325  g.setFileName(filenameCur);
326  g.open(I);
327  g.acquire(I);
328 
329 #if defined VISP_HAVE_X11
330  vpDisplayX display2;
331 #elif defined VISP_HAVE_GTK
332  vpDisplayGTK display2;
333 #elif defined VISP_HAVE_GDI
334  vpDisplayGDI display2;
335 #else
336  vpDisplayOpenCV display2;
337 #endif
338 
339  vpImage<unsigned char> IMatching;
340 
341  keypoints.createImageMatching(I, IMatching);
342 
343  if (opt_display) {
345  display2.init(IMatching, 0, (int)I.getHeight() / vpDisplay::getDownScalingFactor(I) + 80, "IMatching");
346  }
347 
348  bool opt_click = false;
349  double error;
351  while ((opt_display && !g.end()) || (!opt_display && g.getFrameIndex() < 30)) {
352  g.acquire(I);
353 
354  if (opt_display) {
356 
357  // Display image matching
358  keypoints.insertImageMatching(I, IMatching);
359 
360  vpDisplay::display(IMatching);
361  }
362 
363  // Match keypoints and estimate the pose
364  if (keypoints.matchPoint(I, cam, cMo, error, elapsedTime)) {
365  tracker.setCameraParameters(cam);
366  tracker.setPose(I, cMo);
367 
368  if (opt_display) {
369  tracker.display(I, cMo, cam, vpColor::red, 2);
370  vpDisplay::displayFrame(I, cMo, cam, 0.025, vpColor::none, 3);
371 
372  std::vector<vpImagePoint> ransacInliers = keypoints.getRansacInliers();
373  std::vector<vpImagePoint> ransacOutliers = keypoints.getRansacOutliers();
374 
375  for (std::vector<vpImagePoint>::const_iterator it = ransacInliers.begin(); it != ransacInliers.end(); ++it) {
377  vpImagePoint imPt(*it);
378  imPt.set_u(imPt.get_u() + I.getWidth());
379  imPt.set_v(imPt.get_v() + I.getHeight());
380  vpDisplay::displayCircle(IMatching, imPt, 4, vpColor::green);
381  }
382 
383  for (std::vector<vpImagePoint>::const_iterator it = ransacOutliers.begin(); it != ransacOutliers.end();
384  ++it) {
386  vpImagePoint imPt(*it);
387  imPt.set_u(imPt.get_u() + I.getWidth());
388  imPt.set_v(imPt.get_v() + I.getHeight());
389  vpDisplay::displayCircle(IMatching, imPt, 4, vpColor::red);
390  }
391 
392  keypoints.displayMatching(I, IMatching);
393 
394  // Display model in the correct sub-image in IMatching
395  vpCameraParameters cam2;
396  cam2.initPersProjWithoutDistortion(cam.get_px(), cam.get_py(), cam.get_u0() + I.getWidth(),
397  cam.get_v0() + I.getHeight());
398  tracker.setCameraParameters(cam2);
399  tracker.setPose(IMatching, cMo);
400  tracker.display(IMatching, cMo, cam2, vpColor::red, 2);
401  vpDisplay::displayFrame(IMatching, cMo, cam2, 0.025, vpColor::none, 3);
402  }
403  }
404 
405  if (opt_display) {
406  vpDisplay::flush(I);
407  vpDisplay::flush(IMatching);
408  }
409 
410  if (opt_click_allowed && opt_display) {
411  // Click requested to process next image
412  if (opt_click) {
413  vpDisplay::getClick(I, button, true);
414  if (button == vpMouseButton::button3) {
415  opt_click = false;
416  }
417  } else {
418  // Use right click to enable/disable step by step tracking
419  if (vpDisplay::getClick(I, button, false)) {
420  if (button == vpMouseButton::button3) {
421  opt_click = true;
422  } else if (button == vpMouseButton::button1) {
423  break;
424  }
425  }
426  }
427  }
428  }
429 
430  } catch (vpException &e) {
431  std::cerr << e.what() << std::endl;
432  return -1;
433  }
434 
435  std::cout << "testKeyPoint-2 is ok !" << std::endl;
436  return 0;
437 }
438 #else
439 int main()
440 {
441  std::cerr << "You need OpenCV library." << std::endl;
442 
443  return 0;
444 }
445 
446 #endif
virtual unsigned int getClipping() const
Definition: vpMbTracker.h:223
void setMovingEdge(const vpMe &me)
virtual void getPose(vpHomogeneousMatrix &cMo_) const
Definition: vpMbTracker.h:381
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1210
virtual void setAngleDisappear(const double &a)
Definition: vpMbTracker.h:433
Implementation of an homogeneous matrix and operations on such kind of matrices.
void setMaskNumber(const unsigned int &a)
Definition: vpMe.cpp:454
virtual void setDownScalingFactor(unsigned int scale)
Definition: vpDisplay.cpp:232
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:129
void setSampleStep(const double &s)
Definition: vpMe.h:278
void setNbTotalSample(const int &nb)
Definition: vpMe.h:255
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:151
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
static const vpColor none
Definition: vpColor.h:192
error that can be emited by ViSP classes.
Definition: vpException.h:71
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
Definition: vpMe.h:60
Make the complete tracking of an object by using its CAD model.
virtual void setPose(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cdMo)
virtual void setCameraParameters(const vpCameraParameters &camera)
virtual void initFromPose(const vpImage< unsigned char > &I, const std::string &initFile)
void loadConfigFile(const std::string &configFile)
static const vpColor green
Definition: vpColor.h:183
static void flush(const vpImage< unsigned char > &I)
void setMu1(const double &mu_1)
Definition: vpMe.h:241
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
static const vpColor red
Definition: vpColor.h:180
void initPersProjWithoutDistortion(const double px, const double py, const double u0, const double v0)
virtual void setNearClippingDistance(const double &dist)
void open(vpImage< vpRGBa > &I)
static void compute3DForPointsInPolygons(const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, std::vector< cv::KeyPoint > &candidates, const std::vector< vpPolygon > &polygons, const std::vector< std::vector< vpPoint > > &roisPt, std::vector< cv::Point3f > &points, cv::Mat *descriptors=NULL)
Definition: vpKeyPoint.cpp:762
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1435
void setMaskSize(const unsigned int &a)
Definition: vpMe.cpp:461
static void display(const vpImage< unsigned char > &I)
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Generic class defining intrinsic camera parameters.
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:138
void acquire(vpImage< vpRGBa > &I)
virtual void setFarClippingDistance(const double &dist)
void setFileName(const char *filename)
virtual void setAngleAppear(const double &a)
Definition: vpMbTracker.h:422
virtual void initClick(const vpImage< unsigned char > &I, const std::string &initFile, const bool displayHelp=false)
void buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
const char * what() const
static double rad(double deg)
Definition: vpMath.h:102
static void displayCircle(const vpImage< unsigned char > &I, const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1)
void setMu2(const double &mu_2)
Definition: vpMe.h:248
long getFrameIndex() const
virtual void loadModel(const char *modelFile, const bool verbose=false)
unsigned int getHeight() const
Definition: vpImage.h:178
virtual void getCameraParameters(vpCameraParameters &camera) const
Definition: vpMbTracker.h:215
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:207
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, const vpImagePoint &offset=vpImagePoint(0, 0))
Class that allows keypoints detection (and descriptors extraction) and matching thanks to OpenCV libr...
Definition: vpKeyPoint.h:223
unsigned int getDownScalingFactor()
Definition: vpDisplay.h:229
void setThreshold(const double &t)
Definition: vpMe.h:300
void display(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const vpColor &col, const unsigned int thickness=1, const bool displayFullModel=false)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
void setRange(const unsigned int &r)
Definition: vpMe.h:271
virtual void setClipping(const unsigned int &flags)
unsigned int getWidth() const
Definition: vpImage.h:229
virtual std::pair< std::vector< vpPolygon >, std::vector< std::vector< vpPoint > > > getPolygonFaces(const bool orderPolygons=true, const bool useVisibility=true, const bool clipPolygon=false)