Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
testKeyPoint-3.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Test keypoint matching with mostly OpenCV functions calls
32  * to detect potential memory leaks in testKeyPoint.cpp.
33  */
34 
42 #include <iostream>
43 
44 #include <visp3/core/vpConfig.h>
45 
46 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_FEATURES2D)
47 
48 #include <opencv2/features2d/features2d.hpp>
49 
50 #include <visp3/core/vpImage.h>
51 #include <visp3/core/vpIoTools.h>
52 #include <visp3/gui/vpDisplayGDI.h>
53 #include <visp3/gui/vpDisplayGTK.h>
54 #include <visp3/gui/vpDisplayOpenCV.h>
55 #include <visp3/gui/vpDisplayX.h>
56 #include <visp3/io/vpImageIo.h>
57 #include <visp3/io/vpParseArgv.h>
58 #include <visp3/io/vpVideoReader.h>
59 
60 // List of allowed command line options
61 #define GETOPTARGS "cdh"
62 
63 #ifdef ENABLE_VISP_NAMESPACE
64 using namespace VISP_NAMESPACE_NAME;
65 #endif
66 
67 void usage(const char *name, const char *badparam);
68 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
69 
77 void usage(const char *name, const char *badparam)
78 {
79  fprintf(stdout, "\n\
80 Test keypoints matching.\n\
81 \n\
82 SYNOPSIS\n\
83  %s [-c] [-d] [-h]\n",
84  name);
85 
86  fprintf(stdout, "\n\
87 OPTIONS: \n\
88 \n\
89  -c\n\
90  Disable the mouse click. Useful to automate the \n\
91  execution of this program without human intervention.\n\
92 \n\
93  -d \n\
94  Turn off the display.\n\
95 \n\
96  -h\n\
97  Print the help.\n");
98 
99  if (badparam)
100  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
101 }
102 
114 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display)
115 {
116  const char *optarg_;
117  int c;
118  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
119 
120  switch (c) {
121  case 'c':
122  click_allowed = false;
123  break;
124  case 'd':
125  display = false;
126  break;
127  case 'h':
128  usage(argv[0], nullptr);
129  return false;
130  break;
131 
132  default:
133  usage(argv[0], optarg_);
134  return false;
135  break;
136  }
137  }
138 
139  if ((c == 1) || (c == -1)) {
140  // standalone param or error
141  usage(argv[0], nullptr);
142  std::cerr << "ERROR: " << std::endl;
143  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
144  return false;
145  }
146 
147  return true;
148 }
149 
150 template <typename Type>
151 void run_test(const std::string &env_ipath, bool opt_click_allowed, bool opt_display, vpImage<Type> &Iref,
152  vpImage<Type> &Icur, vpImage<Type> &Imatch)
153 {
154 #if VISP_HAVE_DATASET_VERSION >= 0x030600
155  std::string ext("png");
156 #else
157  std::string ext("pgm");
158 #endif
159  // Set the path location of the image sequence
160  std::string dirname = vpIoTools::createFilePath(env_ipath, "mbt/cube");
161 
162  // Build the name of the image files
163  std::string filenameRef = vpIoTools::createFilePath(dirname, "image0000." + ext);
164  vpImageIo::read(Iref, filenameRef);
165  std::string filenameCur = vpIoTools::createFilePath(dirname, "image%04d." + ext);
166 
167  // Init keypoints
168  cv::Ptr<cv::FeatureDetector> detector;
169  cv::Ptr<cv::DescriptorExtractor> extractor;
170  cv::Ptr<cv::DescriptorMatcher> matcher;
171 
172 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
173  detector = cv::ORB::create();
174  extractor = cv::ORB::create();
175 #else
176  detector = cv::FeatureDetector::create("ORB");
177  extractor = cv::DescriptorExtractor::create("ORB");
178 #endif
179  matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
180 
181  std::vector<cv::KeyPoint> trainKeyPoints;
182  cv::Mat matImg, trainDescriptors;
183  vpImageConvert::convert(Iref, matImg);
184  detector->detect(matImg, trainKeyPoints);
185  extractor->compute(matImg, trainKeyPoints, trainDescriptors);
186 
187  vpVideoReader g;
188  g.setFileName(filenameCur);
189  g.open(Icur);
190  g.acquire(Icur);
191 
192  Imatch.resize(Icur.getHeight(), 2 * Icur.getWidth());
193  Imatch.insert(Iref, vpImagePoint(0, 0));
194 
195 #if defined(VISP_HAVE_X11)
196  vpDisplayX display;
197 #elif defined(VISP_HAVE_GTK)
198  vpDisplayGTK display;
199 #elif defined(VISP_HAVE_GDI)
200  vpDisplayGDI display;
201 #elif defined(HAVE_OPENCV_HIGHGUI)
202  vpDisplayOpenCV display;
203 #endif
204 
205  if (opt_display) {
206  display.setDownScalingFactor(vpDisplay::SCALE_AUTO);
207  display.init(Imatch, 0, 0, "ORB keypoints matching");
208  }
209 
210  bool opt_click = false;
212  while (!g.end()) {
213  g.acquire(Icur);
214  Imatch.insert(Icur, vpImagePoint(0, Icur.getWidth()));
215 
216  if (opt_display) {
217  vpDisplay::display(Imatch);
218  }
219 
220  vpImageConvert::convert(Icur, matImg);
221  std::vector<cv::KeyPoint> queryKeyPoints;
222  detector->detect(matImg, queryKeyPoints);
223 
224  cv::Mat queryDescriptors;
225  extractor->compute(matImg, queryKeyPoints, queryDescriptors);
226 
227  std::vector<std::vector<cv::DMatch> > knn_matches;
228  std::vector<cv::DMatch> matches;
229  matcher->knnMatch(queryDescriptors, trainDescriptors, knn_matches, 2);
230  for (std::vector<std::vector<cv::DMatch> >::const_iterator it = knn_matches.begin(); it != knn_matches.end();
231  ++it) {
232  if (it->size() > 1) {
233  double ratio = (*it)[0].distance / (*it)[1].distance;
234  if (ratio < 0.85) {
235  matches.push_back((*it)[0]);
236  }
237  }
238  }
239 
240  if (opt_display) {
241  for (std::vector<cv::DMatch>::const_iterator it = matches.begin(); it != matches.end(); ++it) {
242  vpImagePoint leftPt(trainKeyPoints[(size_t)it->trainIdx].pt.y, trainKeyPoints[(size_t)it->trainIdx].pt.x);
243  vpImagePoint rightPt(queryKeyPoints[(size_t)it->queryIdx].pt.y,
244  queryKeyPoints[(size_t)it->queryIdx].pt.x + Iref.getWidth());
245  vpDisplay::displayLine(Imatch, leftPt, rightPt, vpColor::green);
246  }
247 
248  vpDisplay::flush(Imatch);
249  }
250 
251  // Click requested to process next image
252  if (opt_click_allowed && opt_display) {
253  if (opt_click) {
254  vpDisplay::getClick(Imatch, button, true);
255  if (button == vpMouseButton::button3) {
256  opt_click = false;
257  }
258  }
259  else {
260  // Use right click to enable/disable step by step tracking
261  if (vpDisplay::getClick(Imatch, button, false)) {
262  if (button == vpMouseButton::button3) {
263  opt_click = true;
264  }
265  else if (button == vpMouseButton::button1) {
266  break;
267  }
268  }
269  }
270  }
271  }
272 }
273 
274 int main(int argc, const char **argv)
275 {
276  try {
277  std::string env_ipath;
278  bool opt_click_allowed = true;
279  bool opt_display = true;
280 
281  // Read the command line options
282  if (getOptions(argc, argv, opt_click_allowed, opt_display) == false) {
283  return EXIT_FAILURE;
284  }
285 
286  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
287  // environment variable value
288  env_ipath = vpIoTools::getViSPImagesDataPath();
289 
290  if (env_ipath.empty()) {
291  std::cerr << "Please set the VISP_INPUT_IMAGE_PATH environment "
292  "variable value."
293  << std::endl;
294  return EXIT_FAILURE;
295  }
296 
297  {
298  vpImage<unsigned char> Iref, Icur, Imatch;
299 
300  std::cout << "-- Test on gray level images" << std::endl;
301  run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
302  }
303 
304  {
305  vpImage<vpRGBa> Iref, Icur, Imatch;
306 
307  std::cout << "-- Test on color images" << std::endl;
308  run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
309  }
310 
311  }
312  catch (const vpException &e) {
313  std::cerr << e.what() << std::endl;
314  return EXIT_FAILURE;
315  }
316 
317  std::cout << "testKeyPoint-3 is ok !" << std::endl;
318  return EXIT_SUCCESS;
319 }
320 
321 #else
322 int main()
323 {
324  std::cerr << "You need OpenCV library." << std::endl;
325 
326  return EXIT_SUCCESS;
327 }
328 
329 #endif
static const vpColor green
Definition: vpColor.h:220
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:130
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:133
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
static void flush(const vpImage< unsigned char > &I)
@ SCALE_AUTO
Definition: vpDisplay.h:184
error that can be emitted by ViSP classes.
Definition: vpException.h:60
const char * what() const
Definition: vpException.cpp:71
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:147
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
Definition of the vpImage class member functions.
Definition: vpImage.h:131
unsigned int getWidth() const
Definition: vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:542
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition: vpImage.h:637
unsigned int getHeight() const
Definition: vpImage.h:181
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1053
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1427
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:70
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 open(vpImage< vpRGBa > &I)
void setFileName(const std::string &filename)