37 #include <visp3/vision/vpHandEyeCalibration.h>
39 #define DEBUG_LEVEL1 0
40 #define DEBUG_LEVEL2 0
52 void vpHandEyeCalibration::calibrationVerifrMo(
const std::vector<vpHomogeneousMatrix> &cMo,
53 const std::vector<vpHomogeneousMatrix> &rMe,
56 unsigned int nbPose = (
unsigned int)cMo.size();
57 std::vector<vpTranslationVector> rTo(nbPose);
58 std::vector<vpRotationMatrix> rRo(nbPose);
60 for (
unsigned int i = 0; i < nbPose; i++) {
70 std::cout <<
"Mean " << std::endl;
71 std::cout <<
"Translation: " << meanTrans.
t() << std::endl;
73 std::cout <<
"Rotation : theta (deg) = " <<
vpMath::deg(sqrt(P.sumSquare())) <<
" Matrice : " << std::endl
74 << meanRot << std::endl;
82 for (
unsigned int i = 0; i < nbPose; i++) {
86 double theta = sqrt(P.sumSquare());
87 std::cout <<
"Distance theta between rMo(" << i <<
") and mean (deg) = " <<
vpMath::deg(theta) << std::endl;
90 resRot += theta * theta;
92 resRot = sqrt(resRot / nbPose);
93 std::cout <<
"Mean residual rMo(" << nbPose <<
") - rotation (deg) = " <<
vpMath::deg(resRot) << std::endl;
95 double resTrans = 0.0;
96 for (
unsigned int i = 0; i < nbPose; i++) {
99 std::cout <<
"Distance d between rMo(" << i <<
") and mean (m) = " << sqrt(errTrans.
sumSquare()) << std::endl;
101 resTrans = sqrt(resTrans / nbPose);
102 std::cout <<
"Mean residual rMo(" << nbPose <<
") - translation (m) = " << resTrans << std::endl;
103 double resPos = (resRot * resRot + resTrans * resTrans) * nbPose;
104 resPos = sqrt(resPos / (2 * nbPose));
105 std::cout <<
"Mean residual rMo(" << nbPose <<
") - global = " << resPos << std::endl;
119 int vpHandEyeCalibration::calibrationRotationProcrustes(
const std::vector<vpHomogeneousMatrix> &cMo,
120 const std::vector<vpHomogeneousMatrix> &rMe,
130 unsigned int nbPose = (
unsigned int)cMo.
size();
133 for (
unsigned int i = 0; i < nbPose; i++) {
135 rMe[i].extract(rRei);
136 cMo[i].extract(ciRo);
139 for (
unsigned int j = 0; j < nbPose; j++) {
143 rMe[j].extract(rRej);
144 cMo[j].extract(cjRo);
182 std::cout <<
"Rotation from Procrustes method " << std::endl;
187 residual = A * Ct.
t() - Et.
t();
190 printf(
"Mean residual (rotation) = %lf\n", res);
208 int vpHandEyeCalibration::calibrationRotationTsai(
const std::vector<vpHomogeneousMatrix> &cMo,
213 unsigned int nbPose = (
unsigned int)cMo.
size();
216 for (
unsigned int i = 0; i < nbPose; i++) {
218 rMe[i].extract(rRei);
219 cMo[i].extract(ciRo);
222 for (
unsigned int j = 0; j < nbPose; j++) {
226 rMe[j].extract(rRej);
227 cMo[j].extract(cjRo);
257 std::cout <<
"Tsai method: system A X = B " << std::endl;
258 std::cout <<
"A " << std::endl << A << std::endl;
259 std::cout <<
"B " << std::endl << B << std::endl;
276 double c = 1 / sqrt(1 + norm);
277 double alpha = acos(c);
279 for (
unsigned int i = 0; i < 3; i++)
288 std::cout <<
"Rotation from Tsai method" << std::endl;
292 for (
unsigned int i = 0; i < 3; i++)
295 residual = A * x - B;
298 printf(
"Mean residual (rotation) = %lf\n", res);
316 int vpHandEyeCalibration::calibrationRotationTsaiOld(
const std::vector<vpHomogeneousMatrix> &cMo,
319 unsigned int nbPose = (
unsigned int)cMo.size();
325 for (
unsigned int i = 0; i < nbPose; i++) {
327 rMe[i].extract(rRei);
328 cMo[i].extract(ciRo);
331 for (
unsigned int j = 0; j < nbPose; j++) {
334 rMe[j].extract(rRej);
335 cMo[j].extract(cjRo);
344 double theta = sqrt(rPeij[0] * rPeij[0] + rPeij[1] * rPeij[1] + rPeij[2] * rPeij[2]);
351 for (
unsigned int m = 0; m < 3; m++) {
356 theta = sqrt(cijPo[0] * cijPo[0] + cijPo[1] * cijPo[1] + cijPo[2] * cijPo[2]);
357 for (
unsigned int m = 0; m < 3; m++) {
401 for (
unsigned int i = 0; i < 3; i++)
402 x[i] = 2 * x[i] / sqrt(1 + d);
404 theta = 2 * asin(theta);
406 if (std::fabs(theta) > std::numeric_limits<double>::epsilon()) {
407 for (
unsigned int i = 0; i < 3; i++)
408 x[i] *= theta / (2 * sin(theta / 2));
418 std::cout <<
"Rotation from Old Tsai method" << std::endl;
423 residual = A * x2 - B;
426 printf(
"Mean residual (rotation) = %lf\n", res);
445 int vpHandEyeCalibration::calibrationTranslation(
const std::vector<vpHomogeneousMatrix> &cMo,
452 unsigned int nbPose = (
unsigned int)cMo.size();
457 for (
unsigned int i = 0; i < nbPose; i++) {
458 for (
unsigned int j = 0; j < nbPose; j++) {
499 printf(
"New Hand-eye calibration : ");
500 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
503 residual = A * x - B;
506 printf(
"Mean residual (translation) = %lf\n", res);
525 int vpHandEyeCalibration::calibrationTranslationOld(
const std::vector<vpHomogeneousMatrix> &cMo,
536 unsigned int nbPose = (
unsigned int)cMo.size();
538 for (
unsigned int i = 0; i < nbPose; i++) {
541 rMe[i].extract(rRei);
542 cMo[i].extract(ciRo);
543 rMe[i].extract(rTei);
544 cMo[i].extract(ciTo);
546 for (
unsigned int j = 0; j < nbPose; j++) {
551 rMe[j].extract(rRej);
552 cMo[j].extract(cjRo);
555 rMe[j].extract(rTej);
556 cMo[j].extract(cjTo);
562 rTeij = rRej.
t() * rTeij;
567 b = eRc * cjTo - rReij * eRc * ciTo + rTeij;
590 AeTc = Ap * A.
t() * B;
595 printf(
"Old Hand-eye calibration : ");
596 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
600 residual = A * AeTc - B;
603 for (
unsigned int i = 0; i < residual.
getRows(); i++)
604 res += residual[i] * residual[i];
605 res = sqrt(res / residual.
getRows());
606 printf(
"Mean residual (translation) = %lf\n", res);
624 double vpHandEyeCalibration::calibrationErrVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
625 const std::vector<vpHomogeneousMatrix> &rMe,
628 unsigned int nbPose = (
unsigned int)cMo.size();
637 for (
unsigned int i = 0; i < nbPose; i++) {
638 for (
unsigned int j = 0; j < nbPose; j++) {
665 s = (
vpMatrix(ejRei) - I3) * eTc - eRc * cjTci + ejTei;
671 double resRot, resTrans, resPos;
672 resRot = resTrans = resPos = 0.0;
673 for (
unsigned int i = 0; i < (
unsigned int)errVVS.
size(); i += 6) {
674 resRot += errVVS[i] * errVVS[i];
675 resRot += errVVS[i + 1] * errVVS[i + 1];
676 resRot += errVVS[i + 2] * errVVS[i + 2];
677 resTrans += errVVS[i + 3] * errVVS[i + 3];
678 resTrans += errVVS[i + 4] * errVVS[i + 4];
679 resTrans += errVVS[i + 5] * errVVS[i + 5];
681 resPos = resRot + resTrans;
682 resRot = sqrt(resRot * 2 / errVVS.
size());
683 resTrans = sqrt(resTrans * 2 / errVVS.
size());
684 resPos = sqrt(resPos / errVVS.
size());
687 printf(
"Mean VVS residual - rotation (deg) = %lf\n",
vpMath::deg(resRot));
688 printf(
"Mean VVS residual - translation = %lf\n", resTrans);
689 printf(
"Mean VVS residual - global = %lf\n", resPos);
705 #define NB_ITER_MAX 30
707 int vpHandEyeCalibration::calibrationVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
712 unsigned int nbPose = (
unsigned int)cMo.size();
727 while ((res > 1e-7) && (it < NB_ITER_MAX)) {
729 vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, err);
732 for (
unsigned int i = 0; i < nbPose; i++) {
733 for (
unsigned int j = 0; j < nbPose; j++) {
736 vpMatrix Ls(3, 6), Lv(3, 3), Lw(3, 3);
752 for (
unsigned int m = 0; m < 3; m++)
753 for (
unsigned int n = 0; n < 3; n++) {
755 Ls[m][n + 3] = Lw[m][n];
766 for (
unsigned int m = 0; m < 3; m++)
767 for (
unsigned int n = 0; n < 3; n++) {
769 Ls[m][n + 3] = Lw[m][n];
778 int rank = L.pseudoInverse(Lp);
793 printf(
" Iteration number for NL hand-eye minimization : %d\n", it);
797 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
800 res = sqrt(res / err.getRows());
801 printf(
"Mean residual (rotation+translation) = %lf\n", res);
804 if (it == NB_ITER_MAX)
813 #define HE_TSAI_OROT 1
814 #define HE_TSAI_ORNT 2
815 #define HE_TSAI_NROT 3
816 #define HE_TSAI_NRNT 4
817 #define HE_PROCRUSTES_OT 5
818 #define HE_PROCRUSTES_NT 6
823 if (cMo.size() != rMe.size())
833 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
834 double vmin = resPos;
836 int He_method = HE_I;
840 int err = vpHandEyeCalibration::calibrationRotationTsaiOld(cMo, rMe, eRc);
842 printf(
"\n Problem in solving Hand-Eye Rotation by Old Tsai method \n");
845 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
847 printf(
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Old Tsai method for Rotation\n");
852 printf(
"\nRotation by (old) Tsai, old implementation for translation\n");
853 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
856 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
861 He_method = HE_TSAI_OROT;
865 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
867 printf(
"\n Problem in solving Hand-Eye Translation after Old Tsai method for Rotation\n");
872 printf(
"\nRotation by (old) Tsai, new implementation for translation\n");
873 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
876 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
881 He_method = HE_TSAI_ORNT;
887 err = vpHandEyeCalibration::calibrationRotationTsai(cMo, rMe, eRc);
889 printf(
"\n Problem in solving Hand-Eye Rotation by Tsai method \n");
892 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
894 printf(
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Tsai method for Rotation\n");
899 printf(
"\nRotation by Tsai, old implementation for translation\n");
900 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
903 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
908 He_method = HE_TSAI_NROT;
912 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
914 printf(
"\n Problem in solving Hand-Eye Translation after Tsai method for Rotation \n");
919 printf(
"\nRotation by Tsai, new implementation for translation\n");
920 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
923 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
928 He_method = HE_TSAI_NRNT;
934 err = vpHandEyeCalibration::calibrationRotationProcrustes(cMo, rMe, eRc);
936 printf(
"\n Problem in solving Hand-Eye Rotation by Procrustes method \n");
939 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
941 printf(
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Procrustes method for Rotation\n");
946 printf(
"\nRotation by Procrustes, old implementation for translation\n");
947 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
950 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
955 He_method = HE_PROCRUSTES_OT;
959 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
961 printf(
"\n Problem in solving Hand-Eye Translation after Procrustes method for Rotation\n");
966 printf(
"\nRotation by Procrustes, new implementation for translation\n");
967 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
970 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
975 He_method = HE_PROCRUSTES_NT;
985 if (He_method == HE_I)
986 printf(
"Best method : I !!!, vmin = %lf\n", vmin);
987 if (He_method == HE_TSAI_OROT)
988 printf(
"Best method : TSAI_OROT, vmin = %lf\n", vmin);
989 if (He_method == HE_TSAI_ORNT)
990 printf(
"Best method : TSAI_ORNT, vmin = %lf\n", vmin);
991 if (He_method == HE_TSAI_NROT)
992 printf(
"Best method : TSAI_NROT, vmin = %lf\n", vmin);
993 if (He_method == HE_TSAI_NRNT)
994 printf(
"Best method : TSAI_NRNT, vmin = %lf\n", vmin);
995 if (He_method == HE_PROCRUSTES_OT)
996 printf(
"Best method : PROCRUSTES_OT, vmin = %lf\n", vmin);
997 if (He_method == HE_PROCRUSTES_NT)
998 printf(
"Best method : PROCRUSTES_NT, vmin = %lf\n", vmin);
1002 std::cout <<
"Translation: " << eMc[0][3] <<
" " << eMc[1][3] <<
" " << eMc[2][3] << std::endl;
1007 err = vpHandEyeCalibration::calibrationVVS(cMo, rMe, eMc);
1010 printf(
"\n Problem in solving Hand-Eye Calibration by VVS \n");
1012 printf(
"\nRotation and translation after VVS\n");
1013 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
1023 #undef HE_PROCRUSTES_OT
1024 #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)