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