37 #include <visp3/vision/vpHandEyeCalibration.h>
39 #define DEBUG_LEVEL1 0
40 #define DEBUG_LEVEL2 0
54 void vpHandEyeCalibration::calibrationVerifrMo(
const std::vector<vpHomogeneousMatrix> &cMo,
55 const std::vector<vpHomogeneousMatrix> &rMe,
58 unsigned int nbPose = (
unsigned int)cMo.size();
59 std::vector<vpTranslationVector> rTo(nbPose);
60 std::vector<vpRotationMatrix> rRo(nbPose);
62 for (
unsigned int i = 0; i < nbPose; i++) {
72 std::cout <<
"Mean " << std::endl;
73 std::cout <<
"Translation: " << meanTrans.
t() << std::endl;
75 std::cout <<
"Rotation : theta (deg) = " <<
vpMath::deg(sqrt(P.sumSquare())) <<
" Matrice : " << std::endl
76 << meanRot << std::endl;
84 for (
unsigned int i = 0; i < nbPose; i++) {
88 double theta = sqrt(P.sumSquare());
89 std::cout <<
"Distance theta between rMo(" << i <<
") and mean (deg) = " <<
vpMath::deg(theta) << std::endl;
92 resRot += theta * theta;
94 resRot = sqrt(resRot / nbPose);
95 std::cout <<
"Mean residual rMo(" << nbPose <<
") - rotation (deg) = " <<
vpMath::deg(resRot) << std::endl;
97 double resTrans = 0.0;
98 for (
unsigned int i = 0; i < nbPose; i++) {
101 std::cout <<
"Distance d between rMo(" << i <<
") and mean (m) = " << sqrt(errTrans.
sumSquare()) << std::endl;
103 resTrans = sqrt(resTrans / nbPose);
104 std::cout <<
"Mean residual rMo(" << nbPose <<
") - translation (m) = " << resTrans << std::endl;
105 double resPos = (resRot * resRot + resTrans * resTrans) * nbPose;
106 resPos = sqrt(resPos / (2 * nbPose));
107 std::cout <<
"Mean residual rMo(" << nbPose <<
") - global = " << resPos << std::endl;
121 int vpHandEyeCalibration::calibrationRotationProcrustes(
const std::vector<vpHomogeneousMatrix> &cMo,
122 const std::vector<vpHomogeneousMatrix> &rMe,
132 unsigned int nbPose = (
unsigned int)cMo.
size();
135 for (
unsigned int i = 0; i < nbPose; i++) {
137 rMe[i].extract(rRei);
138 cMo[i].extract(ciRo);
141 for (
unsigned int j = 0; j < nbPose; j++) {
145 rMe[j].extract(rRej);
146 cMo[j].extract(cjRo);
185 std::cout <<
"Rotation from Procrustes method " << std::endl;
190 residual = A * Ct.
t() - Et.
t();
193 printf(
"Mean residual (rotation) = %lf\n", res);
211 int vpHandEyeCalibration::calibrationRotationTsai(
const std::vector<vpHomogeneousMatrix> &cMo,
216 unsigned int nbPose = (
unsigned int)cMo.
size();
219 for (
unsigned int i = 0; i < nbPose; i++) {
221 rMe[i].extract(rRei);
222 cMo[i].extract(ciRo);
225 for (
unsigned int j = 0; j < nbPose; j++) {
229 rMe[j].extract(rRej);
230 cMo[j].extract(cjRo);
261 std::cout <<
"Tsai method: system A X = B " << std::endl;
262 std::cout <<
"A " << std::endl << A << std::endl;
263 std::cout <<
"B " << std::endl << B << std::endl;
280 double c = 1 / sqrt(1 + norm);
281 double alpha = acos(c);
283 for (
unsigned int i = 0; i < 3; i++)
292 std::cout <<
"Rotation from Tsai method" << std::endl;
296 for (
unsigned int i = 0; i < 3; i++)
299 residual = A * x - B;
302 printf(
"Mean residual (rotation) = %lf\n", res);
320 int vpHandEyeCalibration::calibrationRotationTsaiOld(
const std::vector<vpHomogeneousMatrix> &cMo,
323 unsigned int nbPose = (
unsigned int)cMo.size();
329 for (
unsigned int i = 0; i < nbPose; i++) {
331 rMe[i].extract(rRei);
332 cMo[i].extract(ciRo);
335 for (
unsigned int j = 0; j < nbPose; j++) {
338 rMe[j].extract(rRej);
339 cMo[j].extract(cjRo);
348 double theta = sqrt(rPeij[0] * rPeij[0] + rPeij[1] * rPeij[1] + rPeij[2] * rPeij[2]);
355 for (
unsigned int m = 0; m < 3; m++) {
360 theta = sqrt(cijPo[0] * cijPo[0] + cijPo[1] * cijPo[1] + cijPo[2] * cijPo[2]);
361 for (
unsigned int m = 0; m < 3; m++) {
406 for (
unsigned int i = 0; i < 3; i++)
407 x[i] = 2 * x[i] / sqrt(1 + d);
409 theta = 2 * asin(theta);
411 if (std::fabs(theta) > std::numeric_limits<double>::epsilon()) {
412 for (
unsigned int i = 0; i < 3; i++)
413 x[i] *= theta / (2 * sin(theta / 2));
424 std::cout <<
"Rotation from Old Tsai method" << std::endl;
429 residual = A * x2 - B;
432 printf(
"Mean residual (rotation) = %lf\n", res);
451 int vpHandEyeCalibration::calibrationTranslation(
const std::vector<vpHomogeneousMatrix> &cMo,
458 unsigned int nbPose = (
unsigned int)cMo.size();
463 for (
unsigned int i = 0; i < nbPose; i++) {
464 for (
unsigned int j = 0; j < nbPose; j++) {
506 printf(
"New Hand-eye calibration : ");
507 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
510 residual = A * x - B;
513 printf(
"Mean residual (translation) = %lf\n", res);
532 int vpHandEyeCalibration::calibrationTranslationOld(
const std::vector<vpHomogeneousMatrix> &cMo,
543 unsigned int nbPose = (
unsigned int)cMo.size();
545 for (
unsigned int i = 0; i < nbPose; i++) {
548 rMe[i].extract(rRei);
549 cMo[i].extract(ciRo);
550 rMe[i].extract(rTei);
551 cMo[i].extract(ciTo);
553 for (
unsigned int j = 0; j < nbPose; j++) {
558 rMe[j].extract(rRej);
559 cMo[j].extract(cjRo);
562 rMe[j].extract(rTej);
563 cMo[j].extract(cjTo);
569 rTeij = rRej.
t() * rTeij;
574 b = eRc * cjTo - rReij * eRc * ciTo + rTeij;
598 AeTc = Ap * A.
t() * B;
603 printf(
"Old Hand-eye calibration : ");
604 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
608 residual = A * AeTc - B;
611 for (
unsigned int i = 0; i < residual.
getRows(); i++)
612 res += residual[i] * residual[i];
613 res = sqrt(res / residual.
getRows());
614 printf(
"Mean residual (translation) = %lf\n", res);
632 double vpHandEyeCalibration::calibrationErrVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
633 const std::vector<vpHomogeneousMatrix> &rMe,
636 unsigned int nbPose = (
unsigned int)cMo.size();
645 for (
unsigned int i = 0; i < nbPose; i++) {
646 for (
unsigned int j = 0; j < nbPose; j++) {
674 s = (
vpMatrix(ejRei) - I3) * eTc - eRc * cjTci + ejTei;
680 double resRot, resTrans, resPos;
681 resRot = resTrans = resPos = 0.0;
682 for (
unsigned int i = 0; i < (
unsigned int)errVVS.
size(); i += 6) {
683 resRot += errVVS[i] * errVVS[i];
684 resRot += errVVS[i + 1] * errVVS[i + 1];
685 resRot += errVVS[i + 2] * errVVS[i + 2];
686 resTrans += errVVS[i + 3] * errVVS[i + 3];
687 resTrans += errVVS[i + 4] * errVVS[i + 4];
688 resTrans += errVVS[i + 5] * errVVS[i + 5];
690 resPos = resRot + resTrans;
691 resRot = sqrt(resRot * 2 / errVVS.
size());
692 resTrans = sqrt(resTrans * 2 / errVVS.
size());
693 resPos = sqrt(resPos / errVVS.
size());
696 printf(
"Mean VVS residual - rotation (deg) = %lf\n",
vpMath::deg(resRot));
697 printf(
"Mean VVS residual - translation = %lf\n", resTrans);
698 printf(
"Mean VVS residual - global = %lf\n", resPos);
714 #define NB_ITER_MAX 30
716 int vpHandEyeCalibration::calibrationVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
721 unsigned int nbPose = (
unsigned int)cMo.size();
736 while ((res > 1e-7) && (it < NB_ITER_MAX)) {
738 vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, err);
741 for (
unsigned int i = 0; i < nbPose; i++) {
742 for (
unsigned int j = 0; j < nbPose; j++) {
745 vpMatrix Ls(3, 6), Lv(3, 3), Lw(3, 3);
761 for (
unsigned int m = 0; m < 3; m++)
762 for (
unsigned int n = 0; n < 3; n++) {
764 Ls[m][n + 3] = Lw[m][n];
776 for (
unsigned int m = 0; m < 3; m++)
777 for (
unsigned int n = 0; n < 3; n++) {
779 Ls[m][n + 3] = Lw[m][n];
788 int rank = L.pseudoInverse(Lp);
803 printf(
" Iteration number for NL hand-eye minimization : %d\n", it);
807 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
810 res = sqrt(res / err.getRows());
811 printf(
"Mean residual (rotation+translation) = %lf\n", res);
814 if (it == NB_ITER_MAX)
823 #define HE_TSAI_OROT 1
824 #define HE_TSAI_ORNT 2
825 #define HE_TSAI_NROT 3
826 #define HE_TSAI_NRNT 4
827 #define HE_PROCRUSTES_OT 5
828 #define HE_PROCRUSTES_NT 6
833 if (cMo.size() != rMe.size())
843 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
844 double vmin = resPos;
846 int He_method = HE_I;
850 int err = vpHandEyeCalibration::calibrationRotationTsaiOld(cMo, rMe, eRc);
852 printf(
"\n Problem in solving Hand-Eye Rotation by Old Tsai method \n");
855 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
857 printf(
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Old Tsai method for Rotation\n");
862 printf(
"\nRotation by (old) Tsai, old implementation for translation\n");
863 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
866 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
871 He_method = HE_TSAI_OROT;
875 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
877 printf(
"\n Problem in solving Hand-Eye Translation after Old Tsai method for Rotation\n");
882 printf(
"\nRotation by (old) Tsai, new implementation for translation\n");
883 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
886 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
891 He_method = HE_TSAI_ORNT;
897 err = vpHandEyeCalibration::calibrationRotationTsai(cMo, rMe, eRc);
899 printf(
"\n Problem in solving Hand-Eye Rotation by Tsai method \n");
902 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
904 printf(
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Tsai method for Rotation\n");
909 printf(
"\nRotation by Tsai, old implementation for translation\n");
910 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
913 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
918 He_method = HE_TSAI_NROT;
922 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
924 printf(
"\n Problem in solving Hand-Eye Translation after Tsai method for Rotation \n");
929 printf(
"\nRotation by Tsai, new implementation for translation\n");
930 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
933 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
938 He_method = HE_TSAI_NRNT;
944 err = vpHandEyeCalibration::calibrationRotationProcrustes(cMo, rMe, eRc);
946 printf(
"\n Problem in solving Hand-Eye Rotation by Procrustes method \n");
949 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
951 printf(
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Procrustes method for Rotation\n");
956 printf(
"\nRotation by Procrustes, old implementation for translation\n");
957 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
960 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
965 He_method = HE_PROCRUSTES_OT;
969 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
971 printf(
"\n Problem in solving Hand-Eye Translation after Procrustes method for Rotation\n");
976 printf(
"\nRotation by Procrustes, new implementation for translation\n");
977 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
980 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
985 He_method = HE_PROCRUSTES_NT;
995 if (He_method == HE_I)
996 printf(
"Best method : I !!!, vmin = %lf\n", vmin);
997 if (He_method == HE_TSAI_OROT)
998 printf(
"Best method : TSAI_OROT, vmin = %lf\n", vmin);
999 if (He_method == HE_TSAI_ORNT)
1000 printf(
"Best method : TSAI_ORNT, vmin = %lf\n", vmin);
1001 if (He_method == HE_TSAI_NROT)
1002 printf(
"Best method : TSAI_NROT, vmin = %lf\n", vmin);
1003 if (He_method == HE_TSAI_NRNT)
1004 printf(
"Best method : TSAI_NRNT, vmin = %lf\n", vmin);
1005 if (He_method == HE_PROCRUSTES_OT)
1006 printf(
"Best method : PROCRUSTES_OT, vmin = %lf\n", vmin);
1007 if (He_method == HE_PROCRUSTES_NT)
1008 printf(
"Best method : PROCRUSTES_NT, vmin = %lf\n", vmin);
1012 std::cout <<
"Translation: " << eMc[0][3] <<
" " << eMc[1][3] <<
" " << eMc[2][3] << std::endl;
1017 err = vpHandEyeCalibration::calibrationVVS(cMo, rMe, eMc);
1020 printf(
"\n Problem in solving Hand-Eye Calibration by VVS \n");
1022 printf(
"\nRotation and translation after VVS\n");
1023 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
1035 #undef HE_PROCRUSTES_OT
1036 #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)
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
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)