Visual Servoing Platform  version 3.6.1 under development (2024-04-25)
testKeyPoint-3.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 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 
35 #include <iostream>
36 
37 #include <visp3/core/vpConfig.h>
38 
39 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_FEATURES2D)
40 
41 #include <opencv2/features2d/features2d.hpp>
42 
43 #include <visp3/core/vpImage.h>
44 #include <visp3/core/vpIoTools.h>
45 #include <visp3/gui/vpDisplayGDI.h>
46 #include <visp3/gui/vpDisplayGTK.h>
47 #include <visp3/gui/vpDisplayOpenCV.h>
48 #include <visp3/gui/vpDisplayX.h>
49 #include <visp3/io/vpImageIo.h>
50 #include <visp3/io/vpParseArgv.h>
51 #include <visp3/io/vpVideoReader.h>
52 
53 // List of allowed command line options
54 #define GETOPTARGS "cdh"
55 
56 void usage(const char *name, const char *badparam);
57 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
58 
66 void usage(const char *name, const char *badparam)
67 {
68  fprintf(stdout, "\n\
69 Test keypoints matching.\n\
70 \n\
71 SYNOPSIS\n\
72  %s [-c] [-d] [-h]\n",
73  name);
74 
75  fprintf(stdout, "\n\
76 OPTIONS: \n\
77 \n\
78  -c\n\
79  Disable the mouse click. Useful to automate the \n\
80  execution of this program without human intervention.\n\
81 \n\
82  -d \n\
83  Turn off the display.\n\
84 \n\
85  -h\n\
86  Print the help.\n");
87 
88  if (badparam)
89  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
90 }
91 
103 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display)
104 {
105  const char *optarg_;
106  int c;
107  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
108 
109  switch (c) {
110  case 'c':
111  click_allowed = false;
112  break;
113  case 'd':
114  display = false;
115  break;
116  case 'h':
117  usage(argv[0], nullptr);
118  return false;
119  break;
120 
121  default:
122  usage(argv[0], optarg_);
123  return false;
124  break;
125  }
126  }
127 
128  if ((c == 1) || (c == -1)) {
129  // standalone param or error
130  usage(argv[0], nullptr);
131  std::cerr << "ERROR: " << std::endl;
132  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
133  return false;
134  }
135 
136  return true;
137 }
138 
139 template <typename Type>
140 void run_test(const std::string &env_ipath, bool opt_click_allowed, bool opt_display, vpImage<Type> &Iref,
141  vpImage<Type> &Icur, vpImage<Type> &Imatch)
142 {
143 #if VISP_HAVE_DATASET_VERSION >= 0x030600
144  std::string ext("png");
145 #else
146  std::string ext("pgm");
147 #endif
148  // Set the path location of the image sequence
149  std::string dirname = vpIoTools::createFilePath(env_ipath, "mbt/cube");
150 
151  // Build the name of the image files
152  std::string filenameRef = vpIoTools::createFilePath(dirname, "image0000." + ext);
153  vpImageIo::read(Iref, filenameRef);
154  std::string filenameCur = vpIoTools::createFilePath(dirname, "image%04d." + ext);
155 
156  // Init keypoints
157  cv::Ptr<cv::FeatureDetector> detector;
158  cv::Ptr<cv::DescriptorExtractor> extractor;
159  cv::Ptr<cv::DescriptorMatcher> matcher;
160 
161 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
162  detector = cv::ORB::create();
163  extractor = cv::ORB::create();
164 #else
165  detector = cv::FeatureDetector::create("ORB");
166  extractor = cv::DescriptorExtractor::create("ORB");
167 #endif
168  matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
169 
170  std::vector<cv::KeyPoint> trainKeyPoints;
171  cv::Mat matImg, trainDescriptors;
172  vpImageConvert::convert(Iref, matImg);
173  detector->detect(matImg, trainKeyPoints);
174  extractor->compute(matImg, trainKeyPoints, trainDescriptors);
175 
176  vpVideoReader g;
177  g.setFileName(filenameCur);
178  g.open(Icur);
179  g.acquire(Icur);
180 
181  Imatch.resize(Icur.getHeight(), 2 * Icur.getWidth());
182  Imatch.insert(Iref, vpImagePoint(0, 0));
183 
184 #if defined(VISP_HAVE_X11)
186 #elif defined(VISP_HAVE_GTK)
188 #elif defined(VISP_HAVE_GDI)
190 #elif defined(HAVE_OPENCV_HIGHGUI)
192 #endif
193 
194  if (opt_display) {
195  display.setDownScalingFactor(vpDisplay::SCALE_AUTO);
196  display.init(Imatch, 0, 0, "ORB keypoints matching");
197  }
198 
199  bool opt_click = false;
201  while (!g.end()) {
202  g.acquire(Icur);
203  Imatch.insert(Icur, vpImagePoint(0, Icur.getWidth()));
204 
205  if (opt_display) {
206  vpDisplay::display(Imatch);
207  }
208 
209  vpImageConvert::convert(Icur, matImg);
210  std::vector<cv::KeyPoint> queryKeyPoints;
211  detector->detect(matImg, queryKeyPoints);
212 
213  cv::Mat queryDescriptors;
214  extractor->compute(matImg, queryKeyPoints, queryDescriptors);
215 
216  std::vector<std::vector<cv::DMatch> > knn_matches;
217  std::vector<cv::DMatch> matches;
218  matcher->knnMatch(queryDescriptors, trainDescriptors, knn_matches, 2);
219  for (std::vector<std::vector<cv::DMatch> >::const_iterator it = knn_matches.begin(); it != knn_matches.end();
220  ++it) {
221  if (it->size() > 1) {
222  double ratio = (*it)[0].distance / (*it)[1].distance;
223  if (ratio < 0.85) {
224  matches.push_back((*it)[0]);
225  }
226  }
227  }
228 
229  if (opt_display) {
230  for (std::vector<cv::DMatch>::const_iterator it = matches.begin(); it != matches.end(); ++it) {
231  vpImagePoint leftPt(trainKeyPoints[(size_t)it->trainIdx].pt.y, trainKeyPoints[(size_t)it->trainIdx].pt.x);
232  vpImagePoint rightPt(queryKeyPoints[(size_t)it->queryIdx].pt.y,
233  queryKeyPoints[(size_t)it->queryIdx].pt.x + Iref.getWidth());
234  vpDisplay::displayLine(Imatch, leftPt, rightPt, vpColor::green);
235  }
236 
237  vpDisplay::flush(Imatch);
238  }
239 
240  // Click requested to process next image
241  if (opt_click_allowed && opt_display) {
242  if (opt_click) {
243  vpDisplay::getClick(Imatch, button, true);
244  if (button == vpMouseButton::button3) {
245  opt_click = false;
246  }
247  } else {
248  // Use right click to enable/disable step by step tracking
249  if (vpDisplay::getClick(Imatch, button, false)) {
250  if (button == vpMouseButton::button3) {
251  opt_click = true;
252  } else if (button == vpMouseButton::button1) {
253  break;
254  }
255  }
256  }
257  }
258  }
259 }
260 
267 int main(int argc, const char **argv)
268 {
269  try {
270  std::string env_ipath;
271  bool opt_click_allowed = true;
272  bool opt_display = true;
273 
274  // Read the command line options
275  if (getOptions(argc, argv, opt_click_allowed, opt_display) == false) {
276  return EXIT_FAILURE;
277  }
278 
279  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
280  // environment variable value
281  env_ipath = vpIoTools::getViSPImagesDataPath();
282 
283  if (env_ipath.empty()) {
284  std::cerr << "Please set the VISP_INPUT_IMAGE_PATH environment "
285  "variable value."
286  << std::endl;
287  return EXIT_FAILURE;
288  }
289 
290  {
291  vpImage<unsigned char> Iref, Icur, Imatch;
292 
293  std::cout << "-- Test on gray level images" << std::endl;
294  run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
295  }
296 
297  {
298  vpImage<vpRGBa> Iref, Icur, Imatch;
299 
300  std::cout << "-- Test on color images" << std::endl;
301  run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
302  }
303 
304  } catch (const vpException &e) {
305  std::cerr << e.what() << std::endl;
306  return EXIT_FAILURE;
307  }
308 
309  std::cout << "testKeyPoint-3 is ok !" << std::endl;
310  return EXIT_SUCCESS;
311 }
312 
313 #else
314 int main()
315 {
316  std::cerr << "You need OpenCV library." << std::endl;
317 
318  return EXIT_SUCCESS;
319 }
320 
321 #endif
static const vpColor green
Definition: vpColor.h:214
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:128
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:128
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:179
error that can be emitted by ViSP classes.
Definition: vpException.h:59
const char * what() const
Definition: vpException.cpp:70
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:143
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:69
unsigned int getWidth() const
Definition: vpImage.h:245
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:783
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition: vpImage.h:1533
unsigned int getHeight() const
Definition: vpImage.h:184
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1832
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:2195
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 open(vpImage< vpRGBa > &I)
void setFileName(const std::string &filename)
void display(vpImage< unsigned char > &I, const std::string &title)
Display a gray-scale image.