37 #include <visp3/vision/vpHandEyeCalibration.h>
39 #define DEBUG_LEVEL1 0
40 #define DEBUG_LEVEL2 0
56 void vpHandEyeCalibration::calibrationVerifrMo(
const std::vector<vpHomogeneousMatrix> &cMo,
57 const std::vector<vpHomogeneousMatrix> &rMe,
60 unsigned int nbPose = (
unsigned int)cMo.size();
61 std::vector<vpTranslationVector> rTo(nbPose);
62 std::vector<vpRotationMatrix> rRo(nbPose);
64 for (
unsigned int i = 0; i < nbPose; ++i) {
76 std::cout <<
"Mean rMo " << std::endl;
77 std::cout <<
"Translation: " << meanTrans.
t() << std::endl;
79 std::cout <<
"Rotation : theta (deg) = " <<
vpMath::deg(sqrt(P.sumSquare())) <<
" Matrix : " << std::endl
80 << meanRot << std::endl;
88 for (
unsigned int i = 0; i < nbPose; ++i) {
92 double theta = sqrt(P.sumSquare());
93 std::cout <<
"Distance theta between rMo/rMc(" << i <<
") and mean (deg) = " <<
vpMath::deg(theta) << std::endl;
96 resRot += theta * theta;
98 resRot = sqrt(resRot / nbPose);
99 std::cout <<
"Mean residual rMo/rMc(" << nbPose <<
") - rotation (deg) = " <<
vpMath::deg(resRot) << std::endl;
101 double resTrans = 0.0;
102 for (
unsigned int i = 0; i < nbPose; ++i) {
105 std::cout <<
"Distance d between rMo/rMc(" << i <<
") and mean (m) = " << sqrt(errTrans.
sumSquare()) << std::endl;
107 resTrans = sqrt(resTrans / nbPose);
108 std::cout <<
"Mean residual rMo/rMc(" << nbPose <<
") - translation (m) = " << resTrans << std::endl;
109 double resPos = (resRot * resRot + resTrans * resTrans) * nbPose;
110 resPos = sqrt(resPos / (2 * nbPose));
111 std::cout <<
"Mean residual rMo/rMc(" << nbPose <<
") - global = " << resPos << std::endl;
124 void vpHandEyeCalibration::calibrationVerifrMo(
const std::vector<vpHomogeneousMatrix> &cMo,
125 const std::vector<vpHomogeneousMatrix> &rMe,
130 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc, rMo);
143 int vpHandEyeCalibration::calibrationRotationProcrustes(
const std::vector<vpHomogeneousMatrix> &cMo,
144 const std::vector<vpHomogeneousMatrix> &rMe,
154 unsigned int nbPose = (
unsigned int)cMo.
size();
157 for (
unsigned int i = 0; i < nbPose; ++i) {
159 rMe[i].extract(rRei);
160 cMo[i].extract(ciRo);
163 for (
unsigned int j = 0; j < nbPose; ++j) {
167 rMe[j].extract(rRej);
168 cMo[j].extract(cjRo);
207 std::cout <<
"Rotation from Procrustes method " << std::endl;
212 residual = A * Ct.
t() - Et.
t();
215 printf(
"Mean residual (rotation) = %lf\n", res);
233 int vpHandEyeCalibration::calibrationRotationTsai(
const std::vector<vpHomogeneousMatrix> &cMo,
238 unsigned int nbPose = (
unsigned int)cMo.
size();
241 for (
unsigned int i = 0; i < nbPose; ++i) {
243 rMe[i].extract(rRei);
244 cMo[i].extract(ciRo);
247 for (
unsigned int j = 0; j < nbPose; ++j) {
250 rMe[j].extract(rRej);
251 cMo[j].extract(cjRo);
282 std::cout <<
"Tsai method: system A X = B " << std::endl;
283 std::cout <<
"A " << std::endl << A << std::endl;
284 std::cout <<
"B " << std::endl << B << std::endl;
301 double c = 1 / sqrt(1 + norm);
302 double alpha = acos(c);
304 for (
unsigned int i = 0; i < 3; ++i) {
314 std::cout <<
"Rotation from Tsai method" << std::endl;
318 for (
unsigned int i = 0; i < 3; ++i) {
322 residual = A * x - B;
325 printf(
"Mean residual (rotation) = %lf\n", res);
343 int vpHandEyeCalibration::calibrationRotationTsaiOld(
const std::vector<vpHomogeneousMatrix> &cMo,
346 unsigned int nbPose = (
unsigned int)cMo.size();
352 for (
unsigned int i = 0; i < nbPose; ++i) {
354 rMe[i].extract(rRei);
355 cMo[i].extract(ciRo);
358 for (
unsigned int j = 0; j < nbPose; ++j) {
361 rMe[j].extract(rRej);
362 cMo[j].extract(cjRo);
371 double theta = sqrt(rPeij[0] * rPeij[0] + rPeij[1] * rPeij[1] + rPeij[2] * rPeij[2]);
378 for (
unsigned int m = 0; m < 3; m++) {
383 theta = sqrt(cijPo[0] * cijPo[0] + cijPo[1] * cijPo[1] + cijPo[2] * cijPo[2]);
384 for (
unsigned int m = 0; m < 3; m++) {
429 for (
unsigned int i = 0; i < 3; ++i) {
430 x[i] = 2 * x[i] / sqrt(1 + d);
433 theta = 2 * asin(theta);
435 if (std::fabs(theta) > std::numeric_limits<double>::epsilon()) {
436 for (
unsigned int i = 0; i < 3; ++i) {
437 x[i] *= theta / (2 * sin(theta / 2));
450 std::cout <<
"Rotation from Old Tsai method" << std::endl;
455 residual = A * x2 - B;
458 printf(
"Mean residual (rotation) = %lf\n", res);
477 int vpHandEyeCalibration::calibrationTranslation(
const std::vector<vpHomogeneousMatrix> &cMo,
484 unsigned int nbPose = (
unsigned int)cMo.size();
489 for (
unsigned int i = 0; i < nbPose; ++i) {
490 for (
unsigned int j = 0; j < nbPose; ++j) {
532 printf(
"New Hand-eye calibration : ");
533 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
536 residual = A * x - B;
539 printf(
"Mean residual (translation) = %lf\n", res);
558 int vpHandEyeCalibration::calibrationTranslationOld(
const std::vector<vpHomogeneousMatrix> &cMo,
569 unsigned int nbPose = (
unsigned int)cMo.size();
571 for (
unsigned int i = 0; i < nbPose; ++i) {
574 rMe[i].extract(rRei);
575 cMo[i].extract(ciRo);
576 rMe[i].extract(rTei);
577 cMo[i].extract(ciTo);
579 for (
unsigned int j = 0; j < nbPose; ++j) {
582 rMe[j].extract(rRej);
583 cMo[j].extract(cjRo);
586 rMe[j].extract(rTej);
587 cMo[j].extract(cjTo);
593 rTeij = rRej.
t() * rTeij;
598 b = eRc * cjTo - rReij * eRc * ciTo + rTeij;
623 AeTc = Ap * A.
t() * B;
628 printf(
"Old Hand-eye calibration : ");
629 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
633 residual = A * AeTc - B;
636 for (
unsigned int i = 0; i < residual.
getRows(); ++i) {
637 res += residual[i] * residual[i];
639 res = sqrt(res / residual.
getRows());
640 printf(
"Mean residual (translation) = %lf\n", res);
657 double vpHandEyeCalibration::calibrationErrVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
658 const std::vector<vpHomogeneousMatrix> &rMe,
661 unsigned int nbPose = (
unsigned int)cMo.size();
670 for (
unsigned int i = 0; i < nbPose; ++i) {
671 for (
unsigned int j = 0; j < nbPose; ++j) {
698 s = (
vpMatrix(ejRei) - I3) * eTc - eRc * cjTci + ejTei;
704 double resRot, resTrans, resPos;
705 resRot = resTrans = resPos = 0.0;
706 for (
unsigned int i = 0; i < (
unsigned int)errVVS.
size(); i += 6) {
707 resRot += errVVS[i] * errVVS[i];
708 resRot += errVVS[i + 1] * errVVS[i + 1];
709 resRot += errVVS[i + 2] * errVVS[i + 2];
710 resTrans += errVVS[i + 3] * errVVS[i + 3];
711 resTrans += errVVS[i + 4] * errVVS[i + 4];
712 resTrans += errVVS[i + 5] * errVVS[i + 5];
714 resPos = resRot + resTrans;
715 resRot = sqrt(resRot * 2 / errVVS.
size());
716 resTrans = sqrt(resTrans * 2 / errVVS.
size());
717 resPos = sqrt(resPos / errVVS.
size());
720 printf(
"Mean VVS residual - rotation (deg) = %lf\n",
vpMath::deg(resRot));
721 printf(
"Mean VVS residual - translation = %lf\n", resTrans);
722 printf(
"Mean VVS residual - global = %lf\n", resPos);
738 int vpHandEyeCalibration::calibrationVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
742 unsigned int nb_iter_max = 30;
744 unsigned int nbPose = (
unsigned int)cMo.size();
759 while ((res > 1e-7) && (it < nb_iter_max)) {
761 vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, err);
764 for (
unsigned int i = 0; i < nbPose; ++i) {
765 for (
unsigned int j = 0; j < nbPose; ++j) {
768 vpMatrix Ls(3, 6), Lv(3, 3), Lw(3, 3);
784 for (
unsigned int m = 0; m < 3; m++)
785 for (
unsigned int n = 0; n < 3; n++) {
787 Ls[m][n + 3] = Lw[m][n];
799 for (
unsigned int m = 0; m < 3; m++)
800 for (
unsigned int n = 0; n < 3; n++) {
802 Ls[m][n + 3] = Lw[m][n];
811 int rank = L.pseudoInverse(Lp);
826 printf(
" Iteration number for NL hand-eye minimization : %d\n", it);
830 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
833 res = sqrt(res / err.getRows());
834 printf(
"Mean residual (rotation+translation) = %lf\n", res);
837 if (it == nb_iter_max) {
857 #define HE_TSAI_OROT 1
858 #define HE_TSAI_ORNT 2
859 #define HE_TSAI_NROT 3
860 #define HE_TSAI_NRNT 4
861 #define HE_PROCRUSTES_OT 5
862 #define HE_PROCRUSTES_NT 6
865 const std::vector<vpHomogeneousMatrix> &rMe,
868 if (cMo.size() != rMe.size()) {
880 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
881 double vmin = resPos;
883 int He_method = HE_I;
887 int err = vpHandEyeCalibration::calibrationRotationTsaiOld(cMo, rMe, eRc);
889 std::cout <<
"\nProblem in solving Hand-Eye Rotation by Old Tsai method" << std::endl;
893 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
895 std::cout <<
"\nProblem in solving Hand-Eye Translation by Old Tsai method after Old Tsai method for rotation" << std::endl;
901 std::cout <<
"\nRotation by (old) Tsai, old implementation for translation" << std::endl;
902 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
905 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
910 He_method = HE_TSAI_OROT;
914 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
916 std::cout <<
"\n Problem in solving Hand-Eye Translation after Old Tsai method for rotation" << std::endl;
922 std::cout <<
"\nRotation by (old) Tsai, new implementation for translation" << std::endl;
923 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
926 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
931 He_method = HE_TSAI_ORNT;
937 err = vpHandEyeCalibration::calibrationRotationTsai(cMo, rMe, eRc);
939 std::cout <<
"\n Problem in solving Hand-Eye Rotation by Tsai method" << std::endl;
943 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
945 std::cout <<
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Tsai method for rotation" << std::endl;
951 std::cout <<
"\nRotation by Tsai, old implementation for translation" << std::endl;
952 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
955 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
960 He_method = HE_TSAI_NROT;
964 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
966 std::cout <<
"\n Problem in solving Hand-Eye Translation after Tsai method for rotation" << std::endl;
972 std::cout <<
"\nRotation by Tsai, new implementation for translation" << std::endl;
973 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
976 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
981 He_method = HE_TSAI_NRNT;
987 err = vpHandEyeCalibration::calibrationRotationProcrustes(cMo, rMe, eRc);
989 std::cout <<
"\n Problem in solving Hand-Eye Rotation by Procrustes method" << std::endl;
992 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
994 std::cout <<
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Procrustes method for rotation" << std::endl;
1000 std::cout <<
"\nRotation by Procrustes, old implementation for translation" << std::endl;
1001 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
1004 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
1005 if (resPos < vmin) {
1009 He_method = HE_PROCRUSTES_OT;
1013 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
1015 std::cout <<
"\n Problem in solving Hand-Eye Translation after Procrustes method for rotation" << std::endl;
1021 std::cout <<
"\nRotation by Procrustes, new implementation for translation" << std::endl;
1022 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
1025 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
1026 if (resPos < vmin) {
1030 He_method = HE_PROCRUSTES_NT;
1040 if (He_method == HE_I) {
1041 std::cout <<
"Best method : I !!!, vmin = " << vmin << std::endl;
1043 if (He_method == HE_TSAI_OROT) {
1044 std::cout <<
"Best method : TSAI_OROT, vmin = " << vmin << std::endl;
1046 if (He_method == HE_TSAI_ORNT) {
1047 std::cout <<
"Best method : TSAI_ORNT, vmin = " << vmin << std::endl;
1049 if (He_method == HE_TSAI_NROT) {
1050 std::cout <<
"Best method : TSAI_NROT, vmin = " << vmin << std::endl;
1052 if (He_method == HE_TSAI_NRNT) {
1053 std::cout <<
"Best method : TSAI_NRNT, vmin = " << vmin << std::endl;
1055 if (He_method == HE_PROCRUSTES_OT) {
1056 std::cout <<
"Best method : PROCRUSTES_OT, vmin = " << vmin << std::endl;
1058 if (He_method == HE_PROCRUSTES_NT) {
1059 std::cout <<
"Best method : PROCRUSTES_NT, vmin = " << vmin << std::endl;
1064 std::cout <<
"Translation: " << eMc[0][3] <<
" " << eMc[1][3] <<
" " << eMc[2][3] << std::endl;
1069 err = vpHandEyeCalibration::calibrationVVS(cMo, rMe, eMc);
1072 std::cout <<
"\n Problem in solving Hand-Eye Calibration by VVS" << std::endl;
1076 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc, rMo);
1086 #undef HE_PROCRUSTES_OT
1087 #undef HE_PROCRUSTES_NT
unsigned int getCols() const
unsigned int size() const
Return the number of elements of the 2D array.
unsigned int getRows() const
Implementation of column vector and the associated operations.
static vpMatrix skew(const vpColVector &v)
error that can be emitted by ViSP classes.
@ dimensionError
Bad dimension.
static vpHomogeneousMatrix direct(const vpColVector &v)
static int calibrate(const std::vector< vpHomogeneousMatrix > &cMo, const std::vector< vpHomogeneousMatrix > &rMe, vpHomogeneousMatrix &eMc, vpHomogeneousMatrix &rMo)
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
vpHomogeneousMatrix & buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
vpHomogeneousMatrix inverse() const
vpTranslationVector getTranslationVector() const
void extract(vpRotationMatrix &R) const
void insert(const vpRotationMatrix &R)
static double sinc(double x)
static double deg(double rad)
Implementation of a matrix and operations on matrices.
void stack(const vpMatrix &A)
vpMatrix pseudoInverse(double svThreshold=1e-6) const
Implementation of a rotation matrix and operations on such kind of matrices.
vpRotationMatrix t() const
static vpRotationMatrix mean(const std::vector< vpHomogeneousMatrix > &vec_M)
Implementation of a rotation vector as axis-angle minimal representation.
Class that consider the case of a translation vector.
static vpTranslationVector mean(const std::vector< vpHomogeneousMatrix > &vec_M)