Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
testKeyPoint-7.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 saving / loading learning files for vpKeyPoint class.
32  */
33 
40 #include <iomanip>
41 #include <iostream>
42 
43 #include <visp3/core/vpConfig.h>
44 
45 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_FEATURES2D) && defined(HAVE_OPENCV_VIDEO)
46 
47 #include <visp3/core/vpException.h>
48 #include <visp3/core/vpImage.h>
49 #include <visp3/core/vpIoTools.h>
50 #include <visp3/io/vpImageIo.h>
51 #include <visp3/io/vpParseArgv.h>
52 #include <visp3/vision/vpKeyPoint.h>
53 
54 // List of allowed command line options
55 #define GETOPTARGS "cdo:h"
56 
57 #ifdef ENABLE_VISP_NAMESPACE
58 using namespace VISP_NAMESPACE_NAME;
59 #endif
60 
69 void usage(const char *name, const char *badparam, const std::string &opath, const std::string &user)
70 {
71  fprintf(stdout, "\n\
72 Test save / load learning files for vpKeyPoint class.\n\
73 \n\
74 SYNOPSIS\n\
75  %s [-c] [-d] [-h]\n",
76  name);
77 
78  fprintf(stdout, "\n\
79 OPTIONS: \n\
80 \n\
81  -o <output image path> %s\n\
82  Set image output path.\n\
83  From this directory, creates the \"%s\"\n\
84  subdirectory depending on the username, where \n\
85  learning files will be written.\n\
86 \n\
87  -h\n\
88  Print the help.\n",
89  opath.c_str(), user.c_str());
90 
91  if (badparam)
92  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
93 }
94 
106 bool getOptions(int argc, const char **argv, std::string &opath, const std::string &user)
107 {
108  const char *optarg_;
109  int c;
110  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
111 
112  switch (c) {
113  case 'c':
114  break; // not used, to avoid error with default arguments ctest
115  case 'd':
116  break; // not used, to avoid error with default arguments ctest
117  case 'o':
118  opath = optarg_;
119  break;
120  case 'h':
121  usage(argv[0], nullptr, opath, user);
122  return false;
123  break;
124 
125  default:
126  usage(argv[0], optarg_, opath, user);
127  return false;
128  break;
129  return false;
130  break;
131  }
132  }
133 
134  if ((c == 1) || (c == -1)) {
135  // standalone param or error
136  usage(argv[0], nullptr, opath, user);
137  std::cerr << "ERROR: " << std::endl;
138  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
139  return false;
140  }
141 
142  return true;
143 }
144 
153 bool compareKeyPoints(const std::vector<cv::KeyPoint> &keypoints1, const std::vector<cv::KeyPoint> &keypoints2)
154 {
155  if (keypoints1.size() != keypoints2.size()) {
156  return false;
157  }
158 
159  for (size_t cpt = 0; cpt < keypoints1.size(); cpt++) {
160  if (!vpMath::equal(keypoints1[cpt].angle, keypoints2[cpt].angle, std::numeric_limits<float>::epsilon())) {
161  std::cerr << std::fixed << std::setprecision(9) << "keypoints1[cpt].angle=" << keypoints1[cpt].angle
162  << " ; keypoints2[cpt].angle=" << keypoints2[cpt].angle << std::endl;
163  return false;
164  }
165 
166  if (keypoints1[cpt].class_id != keypoints2[cpt].class_id) {
167  std::cerr << "keypoints1[cpt].class_id=" << keypoints1[cpt].class_id
168  << " ; keypoints2[cpt].class_id=" << keypoints2[cpt].class_id << std::endl;
169  return false;
170  }
171 
172  if (keypoints1[cpt].octave != keypoints2[cpt].octave) {
173  std::cerr << "keypoints1[cpt].octave=" << keypoints1[cpt].octave
174  << " ; keypoints2[cpt].octave=" << keypoints2[cpt].octave << std::endl;
175  return false;
176  }
177 
178  if (!vpMath::equal(keypoints1[cpt].pt.x, keypoints2[cpt].pt.x, std::numeric_limits<float>::epsilon())) {
179  std::cerr << std::fixed << std::setprecision(9) << "keypoints1[cpt].pt.x=" << keypoints1[cpt].pt.x
180  << " ; keypoints2[cpt].pt.x=" << keypoints2[cpt].pt.x << std::endl;
181  return false;
182  }
183 
184  if (!vpMath::equal(keypoints1[cpt].pt.y, keypoints2[cpt].pt.y, std::numeric_limits<float>::epsilon())) {
185  std::cerr << std::fixed << std::setprecision(9) << "keypoints1[cpt].pt.y=" << keypoints1[cpt].pt.y
186  << " ; keypoints2[cpt].pt.y=" << keypoints2[cpt].pt.y << std::endl;
187  return false;
188  }
189 
190  if (!vpMath::equal(keypoints1[cpt].response, keypoints2[cpt].response, std::numeric_limits<float>::epsilon())) {
191  std::cerr << std::fixed << std::setprecision(9) << "keypoints1[cpt].response=" << keypoints1[cpt].response
192  << " ; keypoints2[cpt].response=" << keypoints2[cpt].response << std::endl;
193  return false;
194  }
195 
196  if (!vpMath::equal(keypoints1[cpt].size, keypoints2[cpt].size, std::numeric_limits<float>::epsilon())) {
197  std::cerr << std::fixed << std::setprecision(9) << "keypoints1[cpt].size=" << keypoints1[cpt].size
198  << " ; keypoints2[cpt].size=" << keypoints2[cpt].size << std::endl;
199  return false;
200  }
201  }
202 
203  return true;
204 }
205 
214 bool compareDescriptors(const cv::Mat &descriptors1, const cv::Mat &descriptors2)
215 {
216  if (descriptors1.rows != descriptors2.rows || descriptors1.cols != descriptors2.cols ||
217  descriptors1.type() != descriptors2.type()) {
218  return false;
219  }
220 
221  for (int i = 0; i < descriptors1.rows; i++) {
222  for (int j = 0; j < descriptors1.cols; j++) {
223  switch (descriptors1.type()) {
224  case CV_8U:
225  if (descriptors1.at<unsigned char>(i, j) != descriptors2.at<unsigned char>(i, j)) {
226  std::cerr << "descriptors1.at<unsigned char>(i,j)=" << descriptors1.at<unsigned char>(i, j)
227  << " ; descriptors2.at<unsigned char>(i,j)=" << descriptors2.at<unsigned char>(i, j) << std::endl;
228  return false;
229  }
230  break;
231 
232  case CV_8S:
233  if (descriptors1.at<char>(i, j) != descriptors2.at<char>(i, j)) {
234  std::cerr << "descriptors1.at<char>(i,j)=" << descriptors1.at<char>(i, j)
235  << " ; descriptors2.at<char>(i,j)=" << descriptors2.at<char>(i, j) << std::endl;
236  return false;
237  }
238  break;
239 
240  case CV_16U:
241  if (descriptors1.at<unsigned short>(i, j) != descriptors2.at<unsigned short>(i, j)) {
242  std::cerr << "descriptors1.at<unsigned short>(i,j)=" << descriptors1.at<unsigned short>(i, j)
243  << " ; descriptors2.at<unsigned short>(i,j)=" << descriptors2.at<unsigned short>(i, j) << std::endl;
244  return false;
245  }
246  break;
247 
248  case CV_16S:
249  if (descriptors1.at<short>(i, j) != descriptors2.at<short>(i, j)) {
250  std::cerr << "descriptors1.at<short>(i,j)=" << descriptors1.at<short>(i, j)
251  << " ; descriptors2.at<short>(i,j)=" << descriptors2.at<short>(i, j) << std::endl;
252  return false;
253  }
254  break;
255 
256  case CV_32S:
257  if (descriptors1.at<int>(i, j) != descriptors2.at<int>(i, j)) {
258  std::cerr << "descriptors1.at<int>(i,j)=" << descriptors1.at<int>(i, j)
259  << " ; descriptors2.at<int>(i,j)=" << descriptors2.at<int>(i, j) << std::endl;
260  return false;
261  }
262  break;
263 
264  case CV_32F:
265  if (!vpMath::equal(descriptors1.at<float>(i, j), descriptors2.at<float>(i, j),
266  std::numeric_limits<float>::epsilon())) {
267  std::cerr << std::fixed << std::setprecision(9)
268  << "descriptors1.at<float>(i,j)=" << descriptors1.at<float>(i, j)
269  << " ; descriptors2.at<float>(i,j)=" << descriptors2.at<float>(i, j) << std::endl;
270  return false;
271  }
272  break;
273 
274  case CV_64F:
275  if (!vpMath::equal(descriptors1.at<double>(i, j), descriptors2.at<double>(i, j),
276  std::numeric_limits<double>::epsilon())) {
277  std::cerr << std::fixed << std::setprecision(17)
278  << "descriptors1.at<double>(i,j)=" << descriptors1.at<double>(i, j)
279  << " ; descriptors2.at<double>(i,j)=" << descriptors2.at<double>(i, j) << std::endl;
280  return false;
281  }
282  break;
283 
284  default:
285  return false;
286  break;
287  }
288  }
289  }
290 
291  return true;
292 }
293 
294 template <typename Type> void run_test(const std::string &env_ipath, const std::string &opath, vpImage<Type> &I)
295 {
296  std::string filename;
297  // Set the path location of the image sequence
298  std::string dirname = vpIoTools::createFilePath(env_ipath, "Klimt");
299 
300  // Build the name of the image files
301  std::string img_filename = vpIoTools::createFilePath(dirname, "/Klimt.ppm");
302  vpImageIo::read(I, img_filename);
303 
304  vpKeyPoint keyPoints;
305 
306  // Test with binary descriptor
307  {
308  std::cout << "Detect ORB keypoints" << std::endl;
309  std::string keypointName = "ORB";
310  keyPoints.setDetector(keypointName);
311  keyPoints.setExtractor(keypointName);
312 
313  keyPoints.buildReference(I);
314 
315  std::vector<cv::KeyPoint> trainKeyPoints;
316  keyPoints.getTrainKeyPoints(trainKeyPoints);
317  cv::Mat trainDescriptors = keyPoints.getTrainDescriptors();
318  if (trainKeyPoints.empty() || trainDescriptors.empty() || (int)trainKeyPoints.size() != trainDescriptors.rows) {
319  throw vpException(vpException::fatalError, "Problem when detecting "
320  "keypoints or when "
321  "computing descriptors !");
322  }
323 
324  // Save in binary with training images
325  filename = vpIoTools::createFilePath(opath, "bin_with_img");
326  vpIoTools::makeDirectory(filename);
327  filename = vpIoTools::createFilePath(filename, "test_save_in_bin_with_img.bin");
328  std::cout << "Save keypoints in binary with image in: " << filename << std::endl;
329  keyPoints.saveLearningData(filename, true, true);
330 
331  // Test if save is ok
332  if (!vpIoTools::checkFilename(filename)) {
333  std::stringstream ss;
334  ss << "Problem when saving file=" << filename;
335  throw vpException(vpException::ioError, ss.str().c_str());
336  }
337 
338  // Test if read is ok
339  vpKeyPoint read_keypoint1;
340  std::cout << "Read keypoints from file: " << filename << std::endl;
341  read_keypoint1.loadLearningData(filename, true);
342 
343  std::vector<cv::KeyPoint> trainKeyPoints_read;
344  read_keypoint1.getTrainKeyPoints(trainKeyPoints_read);
345  cv::Mat trainDescriptors_read = read_keypoint1.getTrainDescriptors();
346 
347  std::cout << "Compare keypoints" << std::endl;
348  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
349  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved "
350  "in binary with train images saved !");
351  }
352 
353  std::cout << "Compare descriptors" << std::endl;
354  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
355  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
356  "learning file saved in "
357  "binary with train images saved !");
358  }
359 
360  // Save in binary without training images
361  filename = vpIoTools::createFilePath(opath, "bin_without_img");
362  vpIoTools::makeDirectory(filename);
363  filename = vpIoTools::createFilePath(filename, "test_save_in_bin_without_img.bin");
364  std::cout << "Save keypoints in binary without image in: " << filename << std::endl;
365  keyPoints.saveLearningData(filename, true, false);
366 
367  // Test if save is ok
368  if (!vpIoTools::checkFilename(filename)) {
369  std::stringstream ss;
370  ss << "Problem when saving file=" << filename;
371  throw vpException(vpException::ioError, ss.str().c_str());
372  }
373 
374  // Test if read is ok
375  vpKeyPoint read_keypoint2;
376  std::cout << "Read keypoints from file: " << filename << std::endl;
377  read_keypoint2.loadLearningData(filename, true);
378  trainKeyPoints_read.clear();
379  read_keypoint2.getTrainKeyPoints(trainKeyPoints_read);
380  trainDescriptors_read = read_keypoint2.getTrainDescriptors();
381 
382  std::cout << "Compare keypoints" << std::endl;
383  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
384  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved in "
385  "binary without train images !");
386  }
387 
388  std::cout << "Compare descriptors" << std::endl;
389  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
390  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
391  "learning file saved in "
392  "binary without train images !");
393  }
394 
395 #if defined(VISP_HAVE_PUGIXML)
396  // Save in xml with training images
397  filename = vpIoTools::createFilePath(opath, "xml_with_img");
398  vpIoTools::makeDirectory(filename);
399  filename = vpIoTools::createFilePath(filename, "test_save_in_xml_with_img.xml");
400  std::cout << "Save keypoints in xml with image in: " << filename << std::endl;
401  keyPoints.saveLearningData(filename, false, true);
402 
403  // Test if save is ok
404  if (!vpIoTools::checkFilename(filename)) {
405  std::stringstream ss;
406  ss << "Problem when saving file=" << filename;
407  throw vpException(vpException::ioError, ss.str().c_str());
408  }
409 
410  // Test if read is ok
411  vpKeyPoint read_keypoint3;
412  std::cout << "Read keypoints from file: " << filename << std::endl;
413  read_keypoint3.loadLearningData(filename, false);
414  trainKeyPoints_read.clear();
415  read_keypoint3.getTrainKeyPoints(trainKeyPoints_read);
416  trainDescriptors_read = read_keypoint3.getTrainDescriptors();
417 
418  std::cout << "Compare keypoints" << std::endl;
419  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
420  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved in "
421  "xml with train images saved !");
422  }
423 
424  std::cout << "Compare descriptors" << std::endl;
425  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
426  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
427  "learning file saved in "
428  "xml with train images saved !");
429  }
430 
431  // Save in xml without training images
432  filename = vpIoTools::createFilePath(opath, "xml_without_img");
433  vpIoTools::makeDirectory(filename);
434  filename = vpIoTools::createFilePath(filename, "test_save_in_xml_without_img.xml");
435  std::cout << "Save keypoints in xml without image in: " << filename << std::endl;
436  keyPoints.saveLearningData(filename, false, false);
437 
438  // Test if save is ok
439  if (!vpIoTools::checkFilename(filename)) {
440  std::stringstream ss;
441  ss << "Problem when saving file=" << filename;
442  throw vpException(vpException::ioError, ss.str().c_str());
443  }
444 
445  // Test if read is ok
446  vpKeyPoint read_keypoint4;
447  read_keypoint4.loadLearningData(filename, false);
448  trainKeyPoints_read.clear();
449  std::cout << "Read keypoints from file: " << filename << std::endl;
450  read_keypoint4.getTrainKeyPoints(trainKeyPoints_read);
451  trainDescriptors_read = read_keypoint4.getTrainDescriptors();
452 
453  std::cout << "Compare keypoints" << std::endl;
454  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
455  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved in "
456  "xml without train images saved !");
457  }
458 
459  std::cout << "Compare descriptors" << std::endl;
460  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
461  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
462  "learning file saved in "
463  "xml without train images saved !");
464  }
465 #endif
466  std::cout << "Saving / loading learning files with binary descriptor are ok !" << std::endl;
467  }
468 
469 // Test with floating point descriptor
470 #if defined(VISP_HAVE_OPENCV_NONFREE) || \
471  ((VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(VISP_HAVE_OPENCV_XFEATURES2D) || \
472  (VISP_HAVE_OPENCV_VERSION >= 0x030411 && CV_MAJOR_VERSION < 4) || (VISP_HAVE_OPENCV_VERSION >= 0x040400))
473  {
474 #if (VISP_HAVE_OPENCV_VERSION != 0x040504) && (VISP_HAVE_OPENCV_VERSION != 0x040505) && \
475  (VISP_HAVE_OPENCV_VERSION != 0x040600) && (VISP_HAVE_OPENCV_VERSION != 0x040700) && \
476  (VISP_HAVE_OPENCV_VERSION != 0x040900) && (VISP_HAVE_OPENCV_VERSION != 0x040A00) && \
477  (defined(__APPLE__) && defined(__MACH__))
478  // SIFT is known to be unstable with OpenCV 4.5.4 and 4.5.5 on macOS (see #1048)
479  // Same for OpenCV 4.6.0 (see #1106) where it produces an Illegal Instruction error when OpenCV 4.6.0 is
480  // installed with brew. It seems working when OpenCV is build from source
481  std::string keypointName = "SIFT";
482  std::cout << "Use " << keypointName << " keypoints" << std::endl;
483  keyPoints.setDetector(keypointName);
484  keyPoints.setExtractor(keypointName);
485 
486  std::cout << "Detect keypoints" << std::endl;
487  keyPoints.buildReference(I);
488 
489  std::vector<cv::KeyPoint> trainKeyPoints;
490  keyPoints.getTrainKeyPoints(trainKeyPoints);
491  std::cout << "Get descriptors" << std::endl;
492  cv::Mat trainDescriptors = keyPoints.getTrainDescriptors();
493  if (trainKeyPoints.empty() || trainDescriptors.empty() || (int)trainKeyPoints.size() != trainDescriptors.rows) {
494  throw vpException(vpException::fatalError, "Problem when detecting keypoints or when "
495  "computing descriptors (SIFT) !");
496  }
497 
498  // Save in binary with training images
499  filename = vpIoTools::createFilePath(opath, "bin_with_img");
500  vpIoTools::makeDirectory(filename);
501  filename = vpIoTools::createFilePath(filename, "test_save_in_bin_with_img.bin");
502  std::cout << "Save keypoints in binary with image in: " << filename << std::endl;
503  keyPoints.saveLearningData(filename, true, true);
504 
505  // Test if save is ok
506  if (!vpIoTools::checkFilename(filename)) {
507  std::stringstream ss;
508  ss << "Problem when saving file=" << filename;
509  throw vpException(vpException::ioError, ss.str().c_str());
510  }
511 
512  // Test if read is ok
513  vpKeyPoint read_keypoint1;
514  std::cout << "Load keypoints from: " << filename << std::endl;
515  read_keypoint1.loadLearningData(filename, true);
516  std::vector<cv::KeyPoint> trainKeyPoints_read;
517  read_keypoint1.getTrainKeyPoints(trainKeyPoints_read);
518  cv::Mat trainDescriptors_read = read_keypoint1.getTrainDescriptors();
519 
520  std::cout << "Compare keypoints" << std::endl;
521  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
522  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved in "
523  "binary with train images saved !");
524  }
525 
526  std::cout << "Compare descriptors" << std::endl;
527  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
528  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
529  "learning file saved in "
530  "binary with train images saved !");
531  }
532 
533  // Save in binary with no training images
534  filename = vpIoTools::createFilePath(opath, "bin_without_img");
535  vpIoTools::makeDirectory(filename);
536  filename = vpIoTools::createFilePath(filename, "test_save_in_bin_without_img.bin");
537  std::cout << "Save keypoints in binary without image in: " << filename << std::endl;
538  keyPoints.saveLearningData(filename, true, false);
539 
540  // Test if save is ok
541  if (!vpIoTools::checkFilename(filename)) {
542  std::stringstream ss;
543  ss << "Problem when saving file=" << filename;
544  throw vpException(vpException::ioError, ss.str().c_str());
545  }
546 
547  // Test if read is ok
548  vpKeyPoint read_keypoint2;
549  std::cout << "Load keypoints from: " << filename << std::endl;
550  read_keypoint2.loadLearningData(filename, true);
551  trainKeyPoints_read.clear();
552  read_keypoint2.getTrainKeyPoints(trainKeyPoints_read);
553  trainDescriptors_read = read_keypoint2.getTrainDescriptors();
554 
555  std::cout << "Compare keypoints" << std::endl;
556  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
557  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved in "
558  "binary without train images saved !");
559  }
560 
561  std::cout << "Compare descriptors" << std::endl;
562  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
563  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
564  "learning file saved in "
565  "binary without train images saved !");
566  }
567 
568 #if defined(VISP_HAVE_PUGIXML)
569  // Save in xml with training images
570  filename = vpIoTools::createFilePath(opath, "xml_with_img");
571  vpIoTools::makeDirectory(filename);
572  filename = vpIoTools::createFilePath(filename, "test_save_in_xml_with_img.xml");
573  keyPoints.saveLearningData(filename, false, true);
574 
575  // Test if save is ok
576  if (!vpIoTools::checkFilename(filename)) {
577  std::stringstream ss;
578  ss << "Problem when saving file=" << filename;
579  throw vpException(vpException::ioError, ss.str().c_str());
580  }
581 
582  // Test if read is ok
583  vpKeyPoint read_keypoint3;
584  read_keypoint3.loadLearningData(filename, false);
585  trainKeyPoints_read.clear();
586  read_keypoint3.getTrainKeyPoints(trainKeyPoints_read);
587  trainDescriptors_read = read_keypoint3.getTrainDescriptors();
588 
589  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
590  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved in "
591  "xml with train images saved !");
592  }
593 
594  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
595  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
596  "learning file saved in "
597  "xml with train images saved !");
598  }
599 
600  // Save in xml without training images
601  filename = vpIoTools::createFilePath(opath, "xml_without_img");
602  vpIoTools::makeDirectory(filename);
603  filename = vpIoTools::createFilePath(filename, "test_save_in_xml_without_img.xml");
604  keyPoints.saveLearningData(filename, false, false);
605 
606  // Test if save is ok
607  if (!vpIoTools::checkFilename(filename)) {
608  std::stringstream ss;
609  ss << "Problem when saving file=" << filename;
610  throw vpException(vpException::ioError, ss.str().c_str());
611  }
612 
613  // Test if read is ok
614  vpKeyPoint read_keypoint4;
615  read_keypoint4.loadLearningData(filename, false);
616  trainKeyPoints_read.clear();
617  read_keypoint4.getTrainKeyPoints(trainKeyPoints_read);
618  trainDescriptors_read = read_keypoint4.getTrainDescriptors();
619 
620  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
621  throw vpException(vpException::fatalError, "Problem with trainKeyPoints when reading learning file saved in "
622  "xml without train images saved !");
623  }
624 
625  if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
626  throw vpException(vpException::fatalError, "Problem with trainDescriptors when reading "
627  "learning file saved in "
628  "xml without train images saved !");
629  }
630 #endif
631  std::cout << "Saving / loading learning files with floating point descriptor are ok !" << std::endl;
632 
633  // Test vpKeyPoint::reset()
634  vpKeyPoint keypoint_reset;
635 
636  keypointName = "ORB";
637  std::cout << "Use " << keypointName << " as keypoints" << std::endl;
638  keypoint_reset.setDetector(keypointName);
639  keypoint_reset.setExtractor(keypointName);
640 
641  keypoint_reset.buildReference(I);
642  std::cout << keypointName << " keypoints are detected" << std::endl;
643 
644  // reset
645  keypoint_reset.reset();
646 
647  keypointName = "SIFT";
648  std::cout << "Use " << keypointName << " as keypoints" << std::endl;
649  keypoint_reset.setDetector(keypointName);
650  keypoint_reset.setExtractor(keypointName);
651 
652  keypoint_reset.buildReference(I);
653  std::cout << keypointName << " keypoints are detected" << std::endl;
654 
655  std::vector<cv::KeyPoint> trainKeyPoints_reset;
656  keypoint_reset.getTrainKeyPoints(trainKeyPoints_reset);
657  std::cout << "Get descriptors" << std::endl;
658  cv::Mat trainDescriptors_reset = keypoint_reset.getTrainDescriptors();
659 
660  // If reset is ok, we should get the same keypoints and the same descriptors
661  std::cout << "Compare keypoints" << std::endl;
662  if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_reset)) {
663  throw vpException(vpException::fatalError, "Problem with vpKeyPoint::reset() and trainKeyPoints !");
664  }
665 
666  std::cout << "Compare descriptors" << std::endl;
667  if (!compareDescriptors(trainDescriptors, trainDescriptors_reset)) {
668  throw vpException(vpException::fatalError, "Problem with vpKeyPoint::reset() and trainDescriptors !");
669  }
670 
671  std::cout << "vpKeyPoint::reset() is ok with trainKeyPoints and trainDescriptors !" << std::endl;
672 #endif // OpenCV != 4.5.4 on macOS
673  }
674 #endif
675 }
676 
677 int main(int argc, const char **argv)
678 {
679  try {
680  std::string env_ipath;
681  std::string opt_opath;
682  std::string username;
683  std::string opath;
684 
685  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
686  // environment variable value
687  env_ipath = vpIoTools::getViSPImagesDataPath();
688 
689  if (env_ipath.empty()) {
690  throw vpException(vpException::ioError, "Please set the VISP_INPUT_IMAGE_PATH environment variable value.");
691  }
692 
693 // Set the default output path
694 #if defined(_WIN32)
695  opt_opath = "C:/temp";
696 #else
697  opt_opath = "/tmp";
698 #endif
699 
700  // Get the user login name
701  vpIoTools::getUserName(username);
702 
703  // Read the command line options
704  if (getOptions(argc, argv, opt_opath, username) == false) {
705  throw vpException(vpException::fatalError, "getOptions(argc, argv, opt_opath, username) == false");
706  }
707 
708  // Get the option values
709  if (!opt_opath.empty()) {
710  opath = opt_opath;
711  }
712 
713  // Append to the output path string, the login name of the user
714  opath = vpIoTools::createFilePath(opath, username);
715 
716  {
718 
719  std::cout << "-- Test on gray level images" << std::endl;
720  run_test(env_ipath, opath, I);
721  }
722 
723  {
724  vpImage<vpRGBa> I;
725 
726  std::cout << "-- Test on color images" << std::endl;
727  run_test(env_ipath, opath, I);
728  }
729 
730  }
731  catch (const vpException &e) {
732  std::cerr << e.what() << std::endl;
733  return EXIT_FAILURE;
734  }
735 
736  std::cout << "Saving / loading learning files are ok !" << std::endl;
737  std::cout << "testKeyPoint-7 is ok !" << std::endl;
738  return EXIT_SUCCESS;
739 }
740 #else
741 int main()
742 {
743  std::cerr << "You need OpenCV library." << std::endl;
744 
745  return EXIT_SUCCESS;
746 }
747 
748 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ ioError
I/O error.
Definition: vpException.h:67
@ fatalError
Fatal error.
Definition: vpException.h:72
const char * what() const
Definition: vpException.cpp:71
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:147
Definition of the vpImage class member functions.
Definition: vpImage.h:131
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1053
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:786
static std::string getUserName()
Definition: vpIoTools.cpp:285
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1427
static void makeDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:550
Class that allows keypoints detection (and descriptors extraction) and matching thanks to OpenCV libr...
Definition: vpKeyPoint.h:221
void getTrainKeyPoints(std::vector< cv::KeyPoint > &keyPoints) const
cv::Mat getTrainDescriptors() const
Definition: vpKeyPoint.h:1232
void setExtractor(const vpFeatureDescriptorType &extractorType)
Definition: vpKeyPoint.h:1633
void reset()
void loadLearningData(const std::string &filename, bool binaryMode=false, bool append=false)
void saveLearningData(const std::string &filename, bool binaryMode=false, bool saveTrainingImages=true)
void setDetector(const vpFeatureDetectorType &detectorType)
Definition: vpKeyPoint.h:1575
unsigned int buildReference(const vpImage< unsigned char > &I)
Definition: vpKeyPoint.cpp:194
static bool equal(double x, double y, double threshold=0.001)
Definition: vpMath.h:459
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:70