Visual Servoing Platform  version 3.6.1 under development (2024-04-25)
testKeyPoint-6.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 descriptor computation.
32  */
33 
34 #include <iostream>
35 
36 #include <visp3/core/vpConfig.h>
37 
38 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_FEATURES2D) && defined(HAVE_OPENCV_VIDEO)
39 
40 #include <visp3/core/vpImage.h>
41 #include <visp3/core/vpIoTools.h>
42 #include <visp3/gui/vpDisplayGDI.h>
43 #include <visp3/gui/vpDisplayGTK.h>
44 #include <visp3/gui/vpDisplayOpenCV.h>
45 #include <visp3/gui/vpDisplayX.h>
46 #include <visp3/io/vpImageIo.h>
47 #include <visp3/io/vpParseArgv.h>
48 #include <visp3/vision/vpKeyPoint.h>
49 
50 // List of allowed command line options
51 #define GETOPTARGS "cdh"
52 
53 void usage(const char *name, const char *badparam);
54 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
55 
62 void usage(const char *name, const char *badparam)
63 {
64  fprintf(stdout, "\n\
65 Test keypoint descriptor extraction.\n\
66 \n\
67 SYNOPSIS\n\
68  %s [-c] [-d] [-h]\n",
69  name);
70 
71  fprintf(stdout, "\n\
72 OPTIONS: \n\
73 \n\
74  -c\n\
75  Disable the mouse click. Useful to automate the \n\
76  execution of this program without human intervention.\n\
77 \n\
78  -d \n\
79  Turn off the display.\n\
80 \n\
81  -h\n\
82  Print the help.\n");
83 
84  if (badparam)
85  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
86 }
87 
99 bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display)
100 {
101  const char *optarg_;
102  int c;
103  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
104 
105  switch (c) {
106  case 'c':
107  click_allowed = false;
108  break;
109  case 'd':
110  display = false;
111  break;
112  case 'h':
113  usage(argv[0], nullptr);
114  return false;
115  break;
116 
117  default:
118  usage(argv[0], optarg_);
119  return false;
120  break;
121  }
122  }
123 
124  if ((c == 1) || (c == -1)) {
125  // standalone param or error
126  usage(argv[0], nullptr);
127  std::cerr << "ERROR: " << std::endl;
128  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
129  return false;
130  }
131 
132  return true;
133 }
134 
143 std::string getOpenCVType(int type)
144 {
145  std::string type_string = "";
146 
147  switch (type) {
148  case CV_8U:
149  type_string = "CV_8U";
150  break;
151 
152  case CV_8S:
153  type_string = "CV_8S";
154  break;
155 
156  case CV_16U:
157  type_string = "CV_16U";
158  break;
159 
160  case CV_16S:
161  type_string = "CV_16S";
162  break;
163 
164  case CV_32S:
165  type_string = "CV_32S";
166  break;
167 
168  case CV_32F:
169  type_string = "CV_32F";
170  break;
171 
172  case CV_64F:
173  type_string = "CV_64F";
174  break;
175 
176  default:
177  type_string = "Problem with type !";
178  break;
179  }
180 
181  return type_string;
182 }
183 
184 template <typename Type>
185 void run_test(const std::string &env_ipath, bool opt_click_allowed, bool opt_display, vpImage<Type> &Iinput,
186  vpImage<Type> &I)
187 {
188  // Set the path location of the image sequence
189  std::string dirname = vpIoTools::createFilePath(env_ipath, "Klimt");
190 
191  // Build the name of the image files
192  std::string filename = vpIoTools::createFilePath(dirname, "/Klimt.png");
193  vpImageIo::read(Iinput, filename);
194  Iinput.quarterSizeImage(I);
195 
196 #if defined(VISP_HAVE_X11)
198 #elif defined(VISP_HAVE_GTK)
200 #elif defined(VISP_HAVE_GDI)
202 #elif defined(HAVE_OPENCV_HIGHGUI)
204 #endif
205 
206  if (opt_display) {
207  display.init(I, 0, 0, "KeyPoints detection.");
208  }
209 
210  vpKeyPoint keyPoints;
211 
212  std::vector<std::string> descriptorNames;
213 #if defined(VISP_HAVE_OPENCV_NONFREE) || defined(VISP_HAVE_OPENCV_XFEATURES2D) || \
214  (VISP_HAVE_OPENCV_VERSION >= 0x030411 && CV_MAJOR_VERSION < 4) || (VISP_HAVE_OPENCV_VERSION >= 0x040400)
215  descriptorNames.push_back("SIFT");
216 #endif
217 #if defined(VISP_HAVE_OPENCV_NONFREE) || defined(VISP_HAVE_OPENCV_XFEATURES2D)
218  descriptorNames.push_back("SURF");
219 #endif
220  descriptorNames.push_back("ORB");
221 #if (VISP_HAVE_OPENCV_VERSION >= 0x020403)
222  descriptorNames.push_back("BRISK");
223 #endif
224 #if defined(VISP_HAVE_OPENCV_XFEATURES2D) || (VISP_HAVE_OPENCV_VERSION < 0x030000)
225  descriptorNames.push_back("BRIEF");
226 #if (VISP_HAVE_OPENCV_VERSION >= 0x020402)
227  descriptorNames.push_back("FREAK");
228 #endif
229 #endif
230 #if defined(VISP_HAVE_OPENCV_XFEATURES2D)
231  descriptorNames.push_back("DAISY");
232  descriptorNames.push_back("LATCH");
233 #endif
234 #if (VISP_HAVE_OPENCV_VERSION >= 0x030200) && defined(VISP_HAVE_OPENCV_XFEATURES2D)
235  descriptorNames.push_back("VGG");
236  descriptorNames.push_back("BoostDesc");
237 #endif
238 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
239  descriptorNames.push_back("KAZE");
240  descriptorNames.push_back("AKAZE");
241 #endif
242 
243  std::string detectorName = "FAST";
244  keyPoints.setDetector(detectorName);
245  std::vector<cv::KeyPoint> kpts;
246 
247  keyPoints.detect(I, kpts);
248  std::cout << "Nb keypoints detected: " << kpts.size() << " for " << detectorName << " method." << std::endl;
249  if (kpts.empty()) {
250  std::stringstream ss;
251  ss << "No keypoints detected with " << detectorName << " and image:" << filename << "." << std::endl;
252  throw(vpException(vpException::fatalError, ss.str()));
253  }
254 
255  for (std::vector<std::string>::const_iterator itd = descriptorNames.begin(); itd != descriptorNames.end(); ++itd) {
256  keyPoints.setExtractor(*itd);
257 
258  if (*itd == "KAZE") {
259  detectorName = "KAZE";
260  keyPoints.setDetector(detectorName);
261  keyPoints.detect(I, kpts);
262  std::cout << "Nb keypoints detected: " << kpts.size() << " for " << detectorName << " method." << std::endl;
263  if (kpts.empty()) {
264  std::stringstream ss;
265  ss << "No keypoints detected with " << detectorName << " and image:" << filename << "." << std::endl;
266  throw(vpException(vpException::fatalError, ss.str()));
267  }
268  } else if (*itd == "AKAZE") {
269  detectorName = "AKAZE";
270  keyPoints.setDetector(detectorName);
271  keyPoints.detect(I, kpts);
272  std::cout << "Nb keypoints detected: " << kpts.size() << " for " << detectorName << " method." << std::endl;
273  if (kpts.empty()) {
274  std::stringstream ss;
275  ss << "No keypoints detected with " << detectorName << " and image:" << filename << "." << std::endl;
276  throw(vpException(vpException::fatalError, ss.str()));
277  }
278  } else if (*itd == "BoostDesc") {
279 #if (VISP_HAVE_OPENCV_VERSION >= 0x030200) && defined(VISP_HAVE_OPENCV_XFEATURES2D)
280  cv::Ptr<cv::Feature2D> boostDesc = keyPoints.getExtractor("BoostDesc");
281  // Init BIN BOOST descriptor for FAST keypoints
282  boostDesc = cv::xfeatures2d::BoostDesc::create(cv::xfeatures2d::BoostDesc::BINBOOST_256, true, 5.0f);
283 #endif
284  }
285 
286  double t = vpTime::measureTimeMs();
287  cv::Mat descriptor;
288  keyPoints.extract(I, kpts, descriptor);
289  t = vpTime::measureTimeMs() - t;
290 
291  std::cout << "Descriptor: " << descriptor.rows << "x" << descriptor.cols
292  << " (rows x cols) ; type=" << getOpenCVType(descriptor.type()) << " for " << *itd << " method in " << t
293  << " ms." << std::endl;
294  if (descriptor.empty()) {
295  std::stringstream ss;
296  ss << "No descriptor extracted with " << *itd << " and image:" << filename << "." << std::endl;
297  throw(vpException(vpException::fatalError, ss.str()));
298  }
299 
300  if (opt_display) {
302 
303  for (std::vector<cv::KeyPoint>::const_iterator it = kpts.begin(); it != kpts.end(); ++it) {
304  vpImagePoint imPt;
305  imPt.set_uv(it->pt.x, it->pt.y);
306 
308  }
309 
310  vpDisplay::flush(I);
311 
312  if (opt_click_allowed) {
314  }
315  }
316  }
317 
318  std::cout << "\n\n";
319 
320  std::map<vpKeyPoint::vpFeatureDescriptorType, std::string> mapOfDescriptorNames = keyPoints.getExtractorNames();
321 
322  for (int i = 0; i < vpKeyPoint::DESCRIPTOR_TYPE_SIZE; i++) {
324 
325  if (mapOfDescriptorNames[(vpKeyPoint::vpFeatureDescriptorType)i] == "KAZE") {
326  detectorName = "KAZE";
327  keyPoints.setDetector(detectorName);
328  keyPoints.detect(I, kpts);
329  std::cout << "Nb keypoints detected: " << kpts.size() << " for " << detectorName << " method." << std::endl;
330  if (kpts.empty()) {
331  std::stringstream ss;
332  ss << "No keypoints detected with " << detectorName << " and image:" << filename << "." << std::endl;
333  throw(vpException(vpException::fatalError, ss.str()));
334  }
335  } else if (mapOfDescriptorNames[(vpKeyPoint::vpFeatureDescriptorType)i] == "AKAZE") {
336  detectorName = "AKAZE";
337  keyPoints.setDetector(detectorName);
338  keyPoints.detect(I, kpts);
339  std::cout << "Nb keypoints detected: " << kpts.size() << " for " << detectorName << " method." << std::endl;
340  if (kpts.empty()) {
341  std::stringstream ss;
342  ss << "No keypoints detected with " << detectorName << " and image:" << filename << "." << std::endl;
343  throw(vpException(vpException::fatalError, ss.str()));
344  }
345  } else if (mapOfDescriptorNames[(vpKeyPoint::vpFeatureDescriptorType)i] == "BoostDesc") {
346 #if (VISP_HAVE_OPENCV_VERSION >= 0x030200) && defined(VISP_HAVE_OPENCV_XFEATURES2D)
347  detectorName = "FAST";
348  keyPoints.setDetector(detectorName);
349  keyPoints.detect(I, kpts);
350  std::cout << "Nb keypoints detected: " << kpts.size() << " for " << detectorName << " method." << std::endl;
351  if (kpts.empty()) {
352  std::stringstream ss;
353  ss << "No keypoints detected with " << detectorName << " and image:" << filename << "." << std::endl;
354  throw(vpException(vpException::fatalError, ss.str()));
355  }
356 
357  cv::Ptr<cv::Feature2D> boostDesc = keyPoints.getExtractor("BoostDesc");
358  // Init BIN BOOST descriptor for FAST keypoints
359  boostDesc = cv::xfeatures2d::BoostDesc::create(cv::xfeatures2d::BoostDesc::BINBOOST_256, true, 5.0f);
360 #endif
361  }
362 
363  double t = vpTime::measureTimeMs();
364  cv::Mat descriptor;
365  keyPoints.extract(I, kpts, descriptor);
366  t = vpTime::measureTimeMs() - t;
367 
368  std::cout << "Descriptor: " << descriptor.rows << "x" << descriptor.cols
369  << " (rows x cols) ; type=" << getOpenCVType(descriptor.type()) << " for "
370  << mapOfDescriptorNames[(vpKeyPoint::vpFeatureDescriptorType)i] << " method in " << t << " ms."
371  << std::endl;
372  if (descriptor.empty()) {
373  std::stringstream ss;
374  ss << "No descriptor extracted with " << mapOfDescriptorNames[(vpKeyPoint::vpFeatureDescriptorType)i]
375  << " and image:" << filename << "." << std::endl;
376  throw(vpException(vpException::fatalError, ss.str()));
377  }
378 
379  if (opt_display) {
381 
382  for (std::vector<cv::KeyPoint>::const_iterator it = kpts.begin(); it != kpts.end(); ++it) {
383  vpImagePoint imPt;
384  imPt.set_uv(it->pt.x, it->pt.y);
385 
387  }
388 
389  vpDisplay::flush(I);
390 
391  if (opt_click_allowed) {
393  }
394  }
395  }
396 }
397 
403 int main(int argc, const char **argv)
404 {
405  try {
406  std::string env_ipath;
407  bool opt_click_allowed = true;
408  bool opt_display = true;
409 
410  // Read the command line options
411  if (getOptions(argc, argv, opt_click_allowed, opt_display) == false) {
412  exit(EXIT_FAILURE);
413  }
414 
415  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
416  // environment variable value
417  env_ipath = vpIoTools::getViSPImagesDataPath();
418 
419  if (env_ipath.empty()) {
420  std::cerr << "Please set the VISP_INPUT_IMAGE_PATH environment "
421  "variable value."
422  << std::endl;
423  return EXIT_FAILURE;
424  }
425 
426  {
427  vpImage<unsigned char> Iinput, I;
428 
429  std::cout << "-- Test on gray level images" << std::endl;
430  run_test(env_ipath, opt_click_allowed, opt_display, Iinput, I);
431  }
432 
433  {
434  vpImage<vpRGBa> Iinput, I;
435 
436  std::cout << "-- Test on color images" << std::endl;
437  run_test(env_ipath, opt_click_allowed, opt_display, Iinput, I);
438  }
439 
440  } catch (const vpException &e) {
441  std::cerr << e.what() << std::endl;
442  return EXIT_FAILURE;
443  }
444 
445  std::cout << "testKeyPoint-6 is ok !" << std::endl;
446  return EXIT_SUCCESS;
447 }
448 #else
449 #include <cstdlib>
450 
451 int main()
452 {
453  std::cerr << "You need OpenCV library." << std::endl;
454 
455  return EXIT_SUCCESS;
456 }
457 
458 #endif
static const vpColor red
Definition: vpColor.h:211
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 displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void flush(const vpImage< unsigned char > &I)
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ fatalError
Fatal error.
Definition: vpException.h:84
const char * what() const
Definition: vpException.cpp:70
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
void set_uv(double u, double v)
Definition: vpImagePoint.h:352
Definition of the vpImage class member functions.
Definition: vpImage.h:69
void quarterSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1674
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1832
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:2195
Class that allows keypoints detection (and descriptors extraction) and matching thanks to OpenCV libr...
Definition: vpKeyPoint.h:212
void setExtractor(const vpFeatureDescriptorType &extractorType)
Definition: vpKeyPoint.h:1624
void extract(const vpImage< unsigned char > &I, std::vector< cv::KeyPoint > &keyPoints, cv::Mat &descriptors, std::vector< cv::Point3f > *trainPoints=nullptr)
void detect(const vpImage< unsigned char > &I, std::vector< cv::KeyPoint > &keyPoints, const vpRect &rectangle=vpRect())
Definition: vpKeyPoint.cpp:970
vpFeatureDescriptorType
Definition: vpKeyPoint.h:282
@ DESCRIPTOR_TYPE_SIZE
Number of descriptors available.
Definition: vpKeyPoint.h:310
std::map< vpFeatureDescriptorType, std::string > getExtractorNames() const
Definition: vpKeyPoint.h:1094
void setDetector(const vpFeatureDetectorType &detectorType)
Definition: vpKeyPoint.h:1566
cv::Ptr< cv::DescriptorExtractor > getExtractor(const vpFeatureDescriptorType &type) const
Definition: vpKeyPoint.h:1054
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
void display(vpImage< unsigned char > &I, const std::string &title)
Display a gray-scale image.
VISP_EXPORT double measureTimeMs()