Visual Servoing Platform  version 3.6.1 under development (2024-07-18)
vpXmlConfigParserKeyPoint.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  * XML parser to load configuration for vpKeyPoint class.
32  */
33 
41 #include <iostream>
42 
43 #include <visp3/vision/vpXmlConfigParserKeyPoint.h>
44 
45 #include <map>
46 #if defined(VISP_HAVE_PUGIXML)
47 #include <pugixml.hpp>
48 
49 #include <visp3/core/vpException.h>
50 
52 #ifndef DOXYGEN_SHOULD_SKIP_THIS
53 class vpXmlConfigParserKeyPoint::Impl
54 {
55 public:
56  Impl()
57  : m_detectorName("ORB"), m_extractorName("ORB"), m_matcherName("BruteForce-Hamming"),
58  m_matchingFactorThreshold(2.0), m_matchingMethod(ratioDistanceThreshold), m_matchingRatioThreshold(0.85),
59  m_nbRansacIterations(200), m_nbRansacMinInlierCount(100), m_ransacConsensusPercentage(20.0),
60  m_ransacReprojectionError(6.0), m_ransacThreshold(0.01), m_useRansacConsensusPercentage(false),
61  m_useRansacVVS(true)
62  {
63  init();
64  }
65 
69  void init()
70  {
71  m_nodeMap["conf"] = conf;
72  m_nodeMap["detector"] = detector;
73  m_nodeMap["extractor"] = extractor;
74  m_nodeMap["matcher"] = matcher;
75  m_nodeMap["name"] = name;
76  m_nodeMap["matching_method"] = matching_method;
77  m_nodeMap["constantFactorDistanceThreshold"] = constant_factor_distance_threshold;
78  m_nodeMap["stdDistanceThreshold"] = std_distance_threshold;
79  m_nodeMap["ratioDistanceThreshold"] = ratio_distance_threshold;
80  m_nodeMap["stdAndRatioDistanceThreshold"] = std_and_ratio_distance_threshold;
81  m_nodeMap["noFilterMatching"] = no_filter_matching;
82  m_nodeMap["matchingFactorThreshold"] = matching_factor_threshold;
83  m_nodeMap["matchingRatioThreshold"] = matching_ratio_threshold;
84  m_nodeMap["ransac"] = ransac;
85  m_nodeMap["useRansacVVS"] = use_ransac_vvs;
86  m_nodeMap["useRansacConsensusPercentage"] = use_ransac_consensus_percentage;
87  m_nodeMap["nbRansacIterations"] = nb_ransac_iterations;
88  m_nodeMap["ransacReprojectionError"] = ransac_reprojection_error;
89  m_nodeMap["nbRansacMinInlierCount"] = nb_ransac_min_inlier_count;
90  m_nodeMap["ransacThreshold"] = ransac_threshold;
91  m_nodeMap["ransacConsensusPercentage"] = ransac_consensus_percentage;
92  }
93 
94  void parse(const std::string &filename)
95  {
96  pugi::xml_document doc;
97  if (!doc.load_file(filename.c_str())) {
98  throw vpException(vpException::ioError, "Cannot open file: %s", filename.c_str());
99  }
100 
101  bool detector_node = false;
102  bool extractor_node = false;
103  bool matcher_node = false;
104 
105  pugi::xml_node root_node = doc.document_element();
106  for (pugi::xml_node dataNode = root_node.first_child(); dataNode; dataNode = dataNode.next_sibling()) {
107  if (dataNode.type() == pugi::node_element) {
108  std::map<std::string, int>::iterator iter_data = m_nodeMap.find(dataNode.name());
109  if (iter_data != m_nodeMap.end()) {
110  switch (iter_data->second) {
111  case detector:
112  read_detector(dataNode);
113  detector_node = true;
114  break;
115 
116  case extractor:
117  read_extractor(dataNode);
118  extractor_node = true;
119  break;
120 
121  case matcher:
122  read_matcher(dataNode);
123  matcher_node = true;
124  break;
125 
126  case ransac:
127  read_ransac(dataNode);
128  break;
129 
130  default:
131  break;
132  }
133  }
134  }
135  }
136 
137  if (!detector_node) {
138  std::cout << "detector: name: " << m_detectorName << " (default)" << std::endl;
139  }
140 
141  if (!extractor_node) {
142  std::cout << "extractor: name: " << m_extractorName << " (default)" << std::endl;
143  }
144 
145  if (!matcher_node) {
146  std::cout << "matcher: name: " << m_matcherName << " (default)" << std::endl;
147  }
148  }
149 
155  void read_detector(const pugi::xml_node &node)
156  {
157  bool detector_name_node = false;
158 
159  for (pugi::xml_node dataNode = node.first_child(); dataNode; dataNode = dataNode.next_sibling()) {
160  if (dataNode.type() == pugi::node_element) {
161  std::map<std::string, int>::iterator iter_data = m_nodeMap.find(dataNode.name());
162  if (iter_data != m_nodeMap.end()) {
163  switch (iter_data->second) {
164  case name:
165  m_detectorName = dataNode.text().as_string();
166  detector_name_node = true;
167  break;
168 
169  default:
170  break;
171  }
172  }
173  }
174  }
175 
176  if (!detector_name_node)
177  std::cout << "detector : Name : " << m_detectorName << " (default)" << std::endl;
178  else
179  std::cout << "detector : Name : " << m_detectorName << std::endl;
180  }
181 
187  void read_extractor(const pugi::xml_node &node)
188  {
189  bool extractor_name_node = false;
190 
191  for (pugi::xml_node dataNode = node.first_child(); dataNode; dataNode = dataNode.next_sibling()) {
192  if (dataNode.type() == pugi::node_element) {
193  std::map<std::string, int>::iterator iter_data = m_nodeMap.find(dataNode.name());
194  if (iter_data != m_nodeMap.end()) {
195  switch (iter_data->second) {
196  case name:
197  m_extractorName = dataNode.text().as_string();
198  extractor_name_node = true;
199  break;
200 
201  default:
202  break;
203  }
204  }
205  }
206  }
207 
208  if (!extractor_name_node)
209  std::cout << "extractor : Name : " << m_extractorName << " (default)" << std::endl;
210  else
211  std::cout << "extractor : Name : " << m_extractorName << std::endl;
212  }
213 
219  void read_matcher(const pugi::xml_node &node)
220  {
221  bool matcher_name_node = false;
222  bool matching_method_node = false;
223  std::string matchingMethodName = "ratioDistanceThreshold";
224  bool matching_factor_threshold_node = false;
225  bool matching_ratio_threshold_node = false;
226 
227  for (pugi::xml_node dataNode = node.first_child(); dataNode; dataNode = dataNode.next_sibling()) {
228  if (dataNode.type() == pugi::node_element) {
229  std::map<std::string, int>::iterator iter_data = m_nodeMap.find(dataNode.name());
230  if (iter_data != m_nodeMap.end()) {
231  switch (iter_data->second) {
232  case name:
233  m_matcherName = dataNode.text().as_string();
234  matcher_name_node = true;
235  break;
236 
237  case matching_method: {
238  matchingMethodName = dataNode.text().as_string();
239 
240  std::map<std::string, int>::iterator iter_data2 = m_nodeMap.find(matchingMethodName);
241  if (iter_data2 != m_nodeMap.end()) {
242  matching_method_node = true;
243  switch (iter_data2->second) {
244  case constant_factor_distance_threshold:
245  m_matchingMethod = constantFactorDistanceThreshold;
246  break;
247 
248  case std_distance_threshold:
249  m_matchingMethod = stdDistanceThreshold;
250  break;
251 
252  case ratio_distance_threshold:
253  m_matchingMethod = ratioDistanceThreshold;
254  break;
255 
256  case std_and_ratio_distance_threshold:
257  m_matchingMethod = stdAndRatioDistanceThreshold;
258  break;
259 
260  case no_filter_matching:
261  m_matchingMethod = noFilterMatching;
262  break;
263 
264  default:
265  matching_method_node = false;
266  break;
267  }
268  }
269  break;
270  }
271 
272  case matching_factor_threshold:
273  m_matchingFactorThreshold = dataNode.text().as_double();
274  matching_factor_threshold_node = true;
275  break;
276 
277  case matching_ratio_threshold:
278  m_matchingRatioThreshold = dataNode.text().as_double();
279  matching_ratio_threshold_node = true;
280  break;
281 
282  default:
283  break;
284  }
285  }
286  }
287  }
288 
289  if (!matcher_name_node)
290  std::cout << "matcher : Name : " << m_matcherName << " (default)" << std::endl;
291  else
292  std::cout << "matcher : Name : " << m_matcherName << std::endl;
293 
294  if (!matching_method_node)
295  std::cout << "matcher : Filter method : " << matchingMethodName << " (default)" << std::endl;
296  else
297  std::cout << "matcher : Filter method : " << matchingMethodName << std::endl;
298 
299  if (!matching_factor_threshold_node)
300  std::cout << "matcher : matching factor threshold : " << m_matchingFactorThreshold << " (default)" << std::endl;
301  else
302  std::cout << "matcher : matching factor threshold : " << m_matchingFactorThreshold << std::endl;
303 
304  if (!matching_ratio_threshold_node)
305  std::cout << "matcher : matching ratio threshold : " << m_matchingRatioThreshold << " (default)" << std::endl;
306  else
307  std::cout << "matcher : matching ratio threshold : " << m_matchingRatioThreshold << std::endl;
308  }
309 
315  void read_ransac(const pugi::xml_node &node)
316  {
317  bool use_ransac_vvs_node = false;
318  bool use_ransac_consensus_percentage_node = false;
319  bool nb_ransac_iterations_node = false;
320  bool ransac_reprojection_error_node = false;
321  bool nb_ransac_min_inlier_count_node = false;
322  bool ransac_threshold_node = false;
323  bool ransac_consensus_percentage_node = false;
324 
325  for (pugi::xml_node dataNode = node.first_child(); dataNode; dataNode = dataNode.next_sibling()) {
326  if (dataNode.type() == pugi::node_element) {
327  std::map<std::string, int>::iterator iter_data = m_nodeMap.find(dataNode.name());
328  if (iter_data != m_nodeMap.end()) {
329  switch (iter_data->second) {
330  case use_ransac_vvs:
331  m_useRansacVVS = dataNode.text().as_int() != 0;
332  use_ransac_vvs_node = true;
333  break;
334 
335  case use_ransac_consensus_percentage:
336  m_useRansacConsensusPercentage = dataNode.text().as_int() != 0;
337  use_ransac_consensus_percentage_node = true;
338  break;
339 
340  case nb_ransac_iterations:
341  m_nbRansacIterations = dataNode.text().as_int();
342  nb_ransac_iterations_node = true;
343  break;
344 
345  case ransac_reprojection_error:
346  m_ransacReprojectionError = dataNode.text().as_double();
347  ransac_reprojection_error_node = true;
348  break;
349 
350  case nb_ransac_min_inlier_count:
351  m_nbRansacMinInlierCount = dataNode.text().as_int();
352  nb_ransac_min_inlier_count_node = true;
353  break;
354 
355  case ransac_threshold:
356  m_ransacThreshold = dataNode.text().as_double();
357  ransac_threshold_node = true;
358  break;
359 
360  case ransac_consensus_percentage:
361  m_ransacConsensusPercentage = dataNode.text().as_double();
362  ransac_consensus_percentage_node = true;
363  break;
364 
365  default:
366  break;
367  }
368  }
369  }
370  }
371 
372  if (!use_ransac_vvs_node)
373  std::cout << "ransac: use ransac vvs pose estimation: " << m_useRansacVVS << " (default)" << std::endl;
374  else
375  std::cout << "ransac: use ransac vvs pose estimation: " << m_useRansacVVS << std::endl;
376 
377  if (!use_ransac_consensus_percentage_node)
378  std::cout << "ransac: use consensus percentage: " << m_useRansacConsensusPercentage << " (default)" << std::endl;
379  else
380  std::cout << "ransac: use consensus percentage: " << m_useRansacConsensusPercentage << std::endl;
381 
382  if (!nb_ransac_iterations_node)
383  std::cout << "ransac: nb ransac iterations: " << m_nbRansacIterations << " (default)" << std::endl;
384  else
385  std::cout << "ransac: nb ransac iterations: " << m_nbRansacIterations << std::endl;
386 
387  if (!ransac_reprojection_error_node)
388  std::cout << "ransac: ransac reprojection error in pixel (for OpenCV "
389  "function): "
390  << m_ransacReprojectionError << " (default)" << std::endl;
391  else
392  std::cout << "ransac: ransac reprojection error in pixel (for OpenCV "
393  "function): "
394  << m_ransacReprojectionError << std::endl;
395 
396  if (!nb_ransac_min_inlier_count_node)
397  std::cout << "ransac: nb ransac min inlier count: " << m_nbRansacMinInlierCount << " (default)" << std::endl;
398  else
399  std::cout << "ransac: nb ransac min inlier count: " << m_nbRansacMinInlierCount << std::endl;
400 
401  if (!ransac_threshold_node)
402  std::cout << "ransac: ransac threshold in meter (for ViSP function): " << m_ransacThreshold << " (default)"
403  << std::endl;
404  else
405  std::cout << "ransac: ransac threshold in meter (for ViSP function): " << m_ransacThreshold << std::endl;
406 
407  if (!ransac_consensus_percentage_node)
408  std::cout << "ransac: consensus percentage: " << m_ransacConsensusPercentage << " (default)" << std::endl;
409  else
410  std::cout << "ransac: consensus percentage: " << m_ransacConsensusPercentage << std::endl;
411  }
412 
413  std::string getDetectorName() const { return m_detectorName; }
414  std::string getExtractorName() const { return m_extractorName; }
415  std::string getMatcherName() const { return m_matcherName; }
416 
417  double getMatchingFactorThreshold() const { return m_matchingFactorThreshold; }
418  vpMatchingMethodEnum getMatchingMethod() const { return m_matchingMethod; }
419  double getMatchingRatioThreshold() const { return m_matchingRatioThreshold; }
420 
421  int getNbRansacIterations() const { return m_nbRansacIterations; }
422  int getNbRansacMinInlierCount() const { return m_nbRansacMinInlierCount; }
423  double getRansacConsensusPercentage() const { return m_ransacConsensusPercentage; }
424  double getRansacReprojectionError() const { return m_ransacReprojectionError; }
425  double getRansacThreshold() const { return m_ransacThreshold; }
426  bool getUseRansacConsensusPercentage() const { return m_useRansacConsensusPercentage; }
427  bool getUseRansacVVSPoseEstimation() const { return m_useRansacVVS; }
428 
429 protected:
431  enum vpNodeIdentifier
432  {
433  conf,
434  detector,
435  extractor,
436  matcher,
437  name,
438  matching_method,
439  constant_factor_distance_threshold,
442  std_distance_threshold,
444  ratio_distance_threshold,
446  std_and_ratio_distance_threshold,
449  no_filter_matching,
451  matching_factor_threshold,
453  matching_ratio_threshold,
455  ransac,
456  use_ransac_vvs,
457  use_ransac_consensus_percentage,
460  nb_ransac_iterations,
462  ransac_reprojection_error,
464  nb_ransac_min_inlier_count,
466  ransac_threshold,
468  ransac_consensus_percentage
470  };
471 
473  std::string m_detectorName;
475  std::string m_extractorName;
477  std::string m_matcherName;
479  double m_matchingFactorThreshold;
481  vpMatchingMethodEnum m_matchingMethod;
483  double m_matchingRatioThreshold;
485  int m_nbRansacIterations;
487  int m_nbRansacMinInlierCount;
489  double m_ransacConsensusPercentage;
492  double m_ransacReprojectionError;
495  double m_ransacThreshold;
498  // it is based on a fixed number.
499  bool m_useRansacConsensusPercentage;
502  bool m_useRansacVVS;
503  std::map<std::string, int> m_nodeMap;
504 };
505 #endif // DOXYGEN_SHOULD_SKIP_THIS
506 
508 
510 
511 void vpXmlConfigParserKeyPoint::parse(const std::string &filename) { m_impl->parse(filename); }
512 
513 std::string vpXmlConfigParserKeyPoint::getDetectorName() const { return m_impl->getDetectorName(); }
514 
515 std::string vpXmlConfigParserKeyPoint::getExtractorName() const { return m_impl->getExtractorName(); }
516 
517 std::string vpXmlConfigParserKeyPoint::getMatcherName() const { return m_impl->getMatcherName(); }
518 
519 double vpXmlConfigParserKeyPoint::getMatchingFactorThreshold() const { return m_impl->getMatchingFactorThreshold(); }
520 
522 {
523  return m_impl->getMatchingMethod();
524 }
525 
526 double vpXmlConfigParserKeyPoint::getMatchingRatioThreshold() const { return m_impl->getMatchingRatioThreshold(); }
527 
528 int vpXmlConfigParserKeyPoint::getNbRansacIterations() const { return m_impl->getNbRansacIterations(); }
529 
530 int vpXmlConfigParserKeyPoint::getNbRansacMinInlierCount() const { return m_impl->getNbRansacMinInlierCount(); }
531 
533 {
534  return m_impl->getRansacConsensusPercentage();
535 }
536 
537 double vpXmlConfigParserKeyPoint::getRansacReprojectionError() const { return m_impl->getRansacReprojectionError(); }
538 
539 double vpXmlConfigParserKeyPoint::getRansacThreshold() const { return m_impl->getRansacThreshold(); }
540 
542 {
543  return m_impl->getUseRansacConsensusPercentage();
544 }
545 
547 {
548  return m_impl->getUseRansacVVSPoseEstimation();
549 }
550 END_VISP_NAMESPACE
551 #elif !defined(VISP_BUILD_SHARED_LIBS)
552 // Work around to avoid warning: libvisp_core.a(vpXmlConfigParserKeyPoint.cpp.o) has no symbols
553 void dummy_vpXmlConfigParserKeyPoint() { };
554 
555 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ ioError
I/O error.
Definition: vpException.h:67
void parse(const std::string &filename)
vpMatchingMethodEnum getMatchingMethod() const