Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
tutorial-hand-eye-calibration.cpp
1 #include <map>
3 
4 #include <visp3/core/vpIoTools.h>
5 #include <visp3/vision/vpHandEyeCalibration.h>
6 
7 void usage(const char *argv[], int error)
8 {
9  std::cout << "Synopsis" << std::endl
10  << " " << argv[0] << " [--data-path <path>] [--help] [-h]" << std::endl << std::endl;
11  std::cout << "Description" << std::endl
12  << " --data-path <path> Path to the folder containing" << std::endl
13  << " pose_fPe_%d.yaml and pose_cPo_%d.yaml data files." << std::endl
14  << " Default: \"./\"" << std::endl << std::endl
15  << " --help, -h Print this helper message." << std::endl << std::endl;
16  if (error) {
17  std::cout << "Error" << std::endl
18  << " " << "Unsupported parameter " << argv[error] << std::endl;
19  }
20 }
21 
22 int main(int argc, const char *argv[])
23 {
24  std::string data_path = "./";
25  for (int i = 1; i < argc; i++) {
26  if (std::string(argv[i]) == "--data-path" && i+1 < argc) {
27  data_path = std::string(argv[i+1]);
28  i ++;
29  }
30  else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
31  usage(argv, 0);
32  return EXIT_SUCCESS;
33  }
34  else {
35  usage(argv, i);
36  return EXIT_FAILURE;
37  }
38  }
39 
40  std::vector<vpHomogeneousMatrix> cMo;
41  std::vector<vpHomogeneousMatrix> wMe;
43 
44  std::map<long, std::string> map_fPe_files;
45  std::map<long, std::string> map_cPo_files;
46  std::vector<std::string> files = vpIoTools::getDirFiles(data_path);
47  for (unsigned int i = 0; i < files.size(); i++) {
48  long index_fPe = vpIoTools::getIndex(files[i], "pose_fPe_%d.yaml");
49  long index_cPo = vpIoTools::getIndex(files[i], "pose_cPo_%d.yaml");
50  if (index_fPe != -1) {
51  map_fPe_files[index_fPe] = files[i];
52  }
53  if (index_cPo != -1) {
54  map_cPo_files[index_cPo] = files[i];
55  }
56  }
57 
58  if (map_fPe_files.size() == 0) {
59  std::cout << "No pose_fPe_%d.yaml files found. Use --data-path <path> option to modify data path." << std::endl;
60  return EXIT_FAILURE;
61  }
62  if (map_cPo_files.size() == 0) {
63  std::cout << "No pose_cPo_%d.yaml files found. Use --data-path <path> option to modify data path." << std::endl;
64  return EXIT_FAILURE;
65  }
66 
67  for (std::map<long, std::string>::const_iterator it_fPe = map_fPe_files.begin(); it_fPe != map_fPe_files.end(); ++ it_fPe) {
68  std::string file_fPe = it_fPe->second;
69  std::map<long, std::string>::const_iterator it_cPo = map_cPo_files.find(it_fPe->first);
70  if (it_cPo != map_cPo_files.end()) {
71  std::string file_cPo = it_cPo->second;
72  vpPoseVector wPe;
73  if (wPe.loadYAML(file_fPe, wPe) == false) {
74  std::cout << "Unable to read data from " << data_path << "/" << file_fPe << ". Skip data" << std::endl;
75  continue;
76  }
77 
78  vpPoseVector cPo;
79  if (cPo.loadYAML(file_cPo, cPo) == false) {
80  std::cout << "Unable to read data from " << data_path << "/" << file_cPo << ". Skip data" << std::endl;
81  continue;
82  }
83  std::cout << "Use data from " << data_path << "/" << file_fPe << " and from " << data_path << "/" << file_cPo << std::endl;
84  wMe.push_back(vpHomogeneousMatrix(wPe));
85  cMo.push_back(vpHomogeneousMatrix(cPo));
86  }
87  }
88 
89  if (wMe.size() < 3) {
90  std::cout << "Not enough data pairs found." << std::endl;
91  return EXIT_FAILURE;
92  }
93 
94  int ret = vpHandEyeCalibration::calibrate(cMo, wMe, eMc);
95 
96  if (ret == 0) {
97  std::cout << std::endl << "** Hand-eye calibration succeed" << std::endl;
98  std::cout << std::endl << "** Hand-eye (eMc) transformation estimated:" << std::endl;
99  std::cout << eMc << std::endl;
100  std::cout << "** Corresponding pose vector: " << vpPoseVector(eMc).t() << std::endl;
101 
103  std::cout << std::endl << "** Translation [m]: " << eMc[0][3] << " " << eMc[1][3] << " " << eMc[2][3] << std::endl;
104  std::cout << "** Rotation (theta-u representation) [rad]: " << erc.t() << std::endl;
105  std::cout << "** Rotation (theta-u representation) [deg]: " << vpMath::deg(erc[0]) << " " << vpMath::deg(erc[1]) << " " << vpMath::deg(erc[2]) << std::endl;
106  vpQuaternionVector quaternion(eMc.getRotationMatrix());
107  std::cout << "** Rotation (quaternion representation) [rad]: " << quaternion.t() << std::endl;
108 
109  // save eMc
110  std::ofstream file_eMc("eMc.txt");
111  eMc.save(file_eMc);
112 
113  vpPoseVector pose_vec(eMc);
114  std::string output_filename("eMc.yaml");
115  std::cout << std::endl << "Save transformation matrix eMc as a vpPoseVector in " << output_filename << std::endl;
116  pose_vec.saveYAML(output_filename, pose_vec);
117  }
118  else {
119  std::cout << std::endl << "** Hand-eye calibration failed" << std::endl;
120  std::cout << std::endl << "Check your input data and ensure they are covering the half sphere over the chessboard." << std::endl;
121  std::cout << std::endl << "See https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-calibration-extrinsic.html" << std::endl;
122  }
123 
124  return EXIT_SUCCESS;
125 }
126 
vpRowVector t() const
static bool loadYAML(const std::string &filename, vpArray2D< Type > &A, char *header=NULL)
Definition: vpArray2D.h:652
Implementation of an homogeneous matrix and operations on such kind of matrices.
static int calibrate(const std::vector< vpHomogeneousMatrix > &cMo, const std::vector< vpHomogeneousMatrix > &rMe, vpHomogeneousMatrix &eMc)
static std::vector< std::string > getDirFiles(const std::string &dirname)
Definition: vpIoTools.cpp:1929
Implementation of a rotation vector as quaternion angle minimal representation.
static long getIndex(const std::string &filename, const std::string &format)
Definition: vpIoTools.cpp:1573
static double deg(double rad)
Definition: vpMath.h:103
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:151
vpRowVector t() const
void save(std::ofstream &f) const
Implementation of a rotation vector as axis-angle minimal representation.
vpRotationMatrix getRotationMatrix() const