Visual Servoing Platform  version 3.4.0
testKeyPoint-3.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 keypoint matching with mostly OpenCV functions calls
33  * to detect potential memory leaks in testKeyPoint.cpp.
34  *
35  * Authors:
36  * Souriya Trinh
37  *
38  *****************************************************************************/
39 
40 #include <iostream>
41 
42 #include <visp3/core/vpConfig.h>
43 
44 #if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x020301)
45 
46 #include <opencv2/core/core.hpp>
47 #include <opencv2/features2d/features2d.hpp>
48 #include <visp3/core/vpImage.h>
49 #include <visp3/core/vpIoTools.h>
50 #include <visp3/gui/vpDisplayGDI.h>
51 #include <visp3/gui/vpDisplayGTK.h>
52 #include <visp3/gui/vpDisplayOpenCV.h>
53 #include <visp3/gui/vpDisplayX.h>
54 #include <visp3/io/vpImageIo.h>
55 #include <visp3/io/vpParseArgv.h>
56 #include <visp3/io/vpVideoReader.h>
57 
58 // List of allowed command line options
59 #define GETOPTARGS "cdh"
60 
61 void usage(const char *name, const char *badparam);
62 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
63 
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 automate the \n\
84  execution of this program without human 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 
143 template<typename Type>
144 void run_test(const std::string &env_ipath, bool opt_click_allowed, bool opt_display,
145  vpImage<Type> &Iref, vpImage<Type> &Icur, vpImage<Type> &Imatch)
146 {
147  // Set the path location of the image sequence
148  std::string dirname = vpIoTools::createFilePath(env_ipath, "mbt/cube");
149 
150  // Build the name of the image files
151  std::string filenameRef = vpIoTools::createFilePath(dirname, "image0000.pgm");
152  vpImageIo::read(Iref, filenameRef);
153  std::string filenameCur = vpIoTools::createFilePath(dirname, "image%04d.pgm");
154 
155  // Init keypoints
156  cv::Ptr<cv::FeatureDetector> detector;
157  cv::Ptr<cv::DescriptorExtractor> extractor;
158  cv::Ptr<cv::DescriptorMatcher> matcher;
159 
160 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
161  detector = cv::ORB::create();
162  extractor = cv::ORB::create();
163 #else
164  detector = cv::FeatureDetector::create("ORB");
165  extractor = cv::DescriptorExtractor::create("ORB");
166 #endif
167  matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
168 
169  std::vector<cv::KeyPoint> trainKeyPoints;
170  cv::Mat matImg, trainDescriptors;
171  vpImageConvert::convert(Iref, matImg);
172  detector->detect(matImg, trainKeyPoints);
173  extractor->compute(matImg, trainKeyPoints, trainDescriptors);
174 
175  vpVideoReader g;
176  g.setFileName(filenameCur);
177  g.open(Icur);
178  g.acquire(Icur);
179 
180  Imatch.resize(Icur.getHeight(), 2 * Icur.getWidth());
181  Imatch.insert(Iref, vpImagePoint(0, 0));
182 
183 #if defined VISP_HAVE_X11
184  vpDisplayX display;
185 #elif defined VISP_HAVE_GTK
186  vpDisplayGTK display;
187 #elif defined VISP_HAVE_GDI
188  vpDisplayGDI display;
189 #else
190  vpDisplayOpenCV display;
191 #endif
192 
193  if (opt_display) {
195  display.init(Imatch, 0, 0, "ORB keypoints matching");
196  }
197 
198  bool opt_click = false;
200  while (!g.end()) {
201  g.acquire(Icur);
202  Imatch.insert(Icur, vpImagePoint(0, Icur.getWidth()));
203 
204  if (opt_display) {
205  vpDisplay::display(Imatch);
206  }
207 
208  vpImageConvert::convert(Icur, matImg);
209  std::vector<cv::KeyPoint> queryKeyPoints;
210  detector->detect(matImg, queryKeyPoints);
211 
212  cv::Mat queryDescriptors;
213  extractor->compute(matImg, queryKeyPoints, queryDescriptors);
214 
215  std::vector<std::vector<cv::DMatch> > knn_matches;
216  std::vector<cv::DMatch> matches;
217  matcher->knnMatch(queryDescriptors, trainDescriptors, knn_matches, 2);
218  for (std::vector<std::vector<cv::DMatch> >::const_iterator it = knn_matches.begin(); it != knn_matches.end();
219  ++it) {
220  if (it->size() > 1) {
221  double ratio = (*it)[0].distance / (*it)[1].distance;
222  if (ratio < 0.85) {
223  matches.push_back((*it)[0]);
224  }
225  }
226  }
227 
228  if (opt_display) {
229  for (std::vector<cv::DMatch>::const_iterator it = matches.begin(); it != matches.end(); ++it) {
230  vpImagePoint leftPt(trainKeyPoints[(size_t)it->trainIdx].pt.y, trainKeyPoints[(size_t)it->trainIdx].pt.x);
231  vpImagePoint rightPt(queryKeyPoints[(size_t)it->queryIdx].pt.y,
232  queryKeyPoints[(size_t)it->queryIdx].pt.x + Iref.getWidth());
233  vpDisplay::displayLine(Imatch, leftPt, rightPt, vpColor::green);
234  }
235 
236  vpDisplay::flush(Imatch);
237  }
238 
239  // Click requested to process next image
240  if (opt_click_allowed && opt_display) {
241  if (opt_click) {
242  vpDisplay::getClick(Imatch, button, true);
243  if (button == vpMouseButton::button3) {
244  opt_click = false;
245  }
246  } else {
247  // Use right click to enable/disable step by step tracking
248  if (vpDisplay::getClick(Imatch, button, false)) {
249  if (button == vpMouseButton::button3) {
250  opt_click = true;
251  } else if (button == vpMouseButton::button1) {
252  break;
253  }
254  }
255  }
256  }
257  }
258 }
259 
266 int main(int argc, const char **argv)
267 {
268  try {
269  std::string env_ipath;
270  bool opt_click_allowed = true;
271  bool opt_display = true;
272 
273  // Read the command line options
274  if (getOptions(argc, argv, opt_click_allowed, opt_display) == false) {
275  exit(-1);
276  }
277 
278  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
279  // environment variable value
280  env_ipath = vpIoTools::getViSPImagesDataPath();
281 
282  if (env_ipath.empty()) {
283  std::cerr << "Please set the VISP_INPUT_IMAGE_PATH environment "
284  "variable value."
285  << std::endl;
286  return -1;
287  }
288 
289  {
290  vpImage<unsigned char> Iref, Icur, Imatch;
291 
292  std::cout << "-- Test on gray level images" << std::endl;
293  run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
294  }
295 
296  {
297  vpImage<vpRGBa> Iref, Icur, Imatch;
298 
299  std::cout << "-- Test on color images" << std::endl;
300  run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
301  }
302 
303  } catch (const vpException &e) {
304  std::cerr << e.what() << std::endl;
305  return -1;
306  }
307 
308  std::cout << "testKeyPoint-3 is ok !" << std::endl;
309  return 0;
310 }
311 #else
312 int main()
313 {
314  std::cerr << "You need OpenCV library." << std::endl;
315 
316  return 0;
317 }
318 
319 #endif
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1202
unsigned int getWidth() const
Definition: vpImage.h:246
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
virtual void setDownScalingFactor(unsigned int scale)
Definition: vpDisplay.cpp:231
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:150
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
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="")
static const vpColor green
Definition: vpColor.h:220
static void flush(const vpImage< unsigned char > &I)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
void open(vpImage< vpRGBa > &I)
const char * what() const
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1446
static void display(const vpImage< unsigned char > &I)
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:134
void acquire(vpImage< vpRGBa > &I)
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition: vpImage.h:1115
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:244
void setFileName(const std::string &filename)
unsigned int getHeight() const
Definition: vpImage.h:188
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:87
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
Definition of the vpImage class member functions.
Definition: vpImage.h:126