37#include <visp3/vision/vpHandEyeCalibration.h>
56 void vpHandEyeCalibration::calibrationVerifrMo(
const std::vector<vpHomogeneousMatrix> &cMo,
57 const std::vector<vpHomogeneousMatrix> &rMe,
60 unsigned int nbPose =
static_cast<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) {
65 vpHomogeneousMatrix rMo = rMe[
i] * eMc *
cMo[
i];
76 std::cout <<
"Mean rMo " << std::endl;
77 std::cout <<
"Translation: " << meanTrans.
t() << std::endl;
78 vpThetaUVector P(meanRot);
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) {
89 vpRotationMatrix
R = meanRot.
t() * rRo[
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) {
103 vpColVector errTrans = vpColVector(rTo[i] - meanTrans);
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;
124void vpHandEyeCalibration::calibrationVerifrMo(
const std::vector<vpHomogeneousMatrix> &cMo,
125 const std::vector<vpHomogeneousMatrix> &rMe,
128 vpHomogeneousMatrix rMo;
130 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc, rMo);
143int vpHandEyeCalibration::calibrationRotationProcrustes(
const std::vector<vpHomogeneousMatrix> &cMo,
144 const std::vector<vpHomogeneousMatrix> &rMe,
154 unsigned int nbPose =
static_cast<unsigned int>(
cMo.size());
157 for (
unsigned int i = 0;
i < nbPose; ++
i) {
158 vpRotationMatrix rRei, ciRo;
159 rMe[
i].extract(rRei);
160 cMo[
i].extract(ciRo);
163 for (
unsigned int j = 0;
j < nbPose; ++
j) {
166 vpRotationMatrix rRej, cjRo;
167 rMe[
j].extract(rRej);
168 cMo[
j].extract(cjRo);
171 vpRotationMatrix ejRei = rRej.
t() * rRei;
172 vpThetaUVector ejPei(ejRei);
173 vpColVector xe = vpColVector(ejPei);
175 vpRotationMatrix cjRci = cjRo * ciRo.
t();
176 vpThetaUVector cjPci(cjRci);
177 vpColVector xc = vpColVector(cjPci);
203 eRc = vpRotationMatrix(A);
207 vpThetaUVector ePc(eRc);
208 std::cout <<
"Rotation from Procrustes method " << std::endl;
213 residual = A * Ct.
t() - Et.
t();
216 printf(
"Mean residual (rotation) = %lf\n", res);
234int vpHandEyeCalibration::calibrationRotationTsai(
const std::vector<vpHomogeneousMatrix> &cMo,
239 unsigned int nbPose =
static_cast<unsigned int>(
cMo.size());
242 for (
unsigned int i = 0;
i < nbPose; ++
i) {
243 vpRotationMatrix rRei, ciRo;
244 rMe[
i].extract(rRei);
245 cMo[
i].extract(ciRo);
248 for (
unsigned int j = 0;
j < nbPose; ++
j) {
250 vpRotationMatrix rRej, cjRo;
251 rMe[
j].extract(rRej);
252 cMo[
j].extract(cjRo);
255 vpRotationMatrix ejRei = rRej.
t() * rRei;
256 vpThetaUVector ejPei(ejRei);
258 vpRotationMatrix cjRci = cjRo * ciRo.
t();
259 vpThetaUVector cjPci(cjRci);
267 b =
static_cast<vpColVector
>(cjPci) -
static_cast<vpColVector
>(ejPei);
283 std::cout <<
"Tsai method: system A X = B " << std::endl;
284 std::cout <<
"A " << std::endl << A << std::endl;
285 std::cout <<
"B " << std::endl << B << std::endl;
297 vpColVector
x = Ap * B;
302 double norm =
x.sumSquare();
303 double c = 1 / sqrt(1 + norm);
304 double alpha = acos(c);
306 for (
unsigned int i = 0;
i < 3; ++
i) {
311 vpThetaUVector xP(x[0], x[1], x[2]);
312 eRc = vpRotationMatrix(xP);
316 std::cout <<
"Rotation from Tsai method" << std::endl;
320 for (
unsigned int i = 0;
i < 3; ++
i) {
323 vpColVector residual;
324 residual = A *
x - B;
327 printf(
"Mean residual (rotation) = %lf\n", res);
345int vpHandEyeCalibration::calibrationRotationTsaiOld(
const std::vector<vpHomogeneousMatrix> &cMo,
348 unsigned int nbPose =
static_cast<unsigned int>(
cMo.size());
354 for (
unsigned int i = 0;
i < nbPose; ++
i) {
355 vpRotationMatrix rRei, ciRo;
356 rMe[
i].extract(rRei);
357 cMo[
i].extract(ciRo);
360 for (
unsigned int j = 0;
j < nbPose; ++
j) {
362 vpRotationMatrix rRej, cjRo;
363 rMe[
j].extract(rRej);
364 cMo[
j].extract(cjRo);
367 vpRotationMatrix rReij = rRej.
t() * rRei;
369 vpRotationMatrix cijRo = cjRo * ciRo.
t();
371 vpThetaUVector rPeij(rReij);
373 double theta = sqrt(rPeij[0] * rPeij[0] + rPeij[1] * rPeij[1] + rPeij[2] * rPeij[2]);
380 for (
unsigned int m = 0; m < 3; m++) {
384 vpThetaUVector cijPo(cijRo);
385 theta = sqrt(cijPo[0] * cijPo[0] + cijPo[1] * cijPo[1] + cijPo[2] * cijPo[2]);
386 for (
unsigned int m = 0; m < 3; m++) {
398 b =
static_cast<vpColVector
>(cijPo) -
static_cast<vpColVector
>(rPeij);
418 vpMatrix AtA = A.
AtA();
431 double d =
x.sumSquare();
432 for (
unsigned int i = 0;
i < 3; ++
i) {
433 x[
i] = 2 *
x[
i] / sqrt(1 + d);
435 theta = sqrt(
x.sumSquare()) / 2;
436 theta = 2 * asin(theta);
438 if (std::fabs(theta) > std::numeric_limits<double>::epsilon()) {
439 for (
unsigned int i = 0;
i < 3; ++
i) {
440 x[
i] *= theta / (2 * sin(theta / 2));
448 vpThetaUVector xP(x[0], x[1], x[2]);
449 eRc = vpRotationMatrix(xP);
453 std::cout <<
"Rotation from Old Tsai method" << std::endl;
457 vpColVector residual;
458 residual = A * x2 - B;
461 printf(
"Mean residual (rotation) = %lf\n", res);
480int vpHandEyeCalibration::calibrationTranslation(
const std::vector<vpHomogeneousMatrix> &cMo,
487 unsigned int nbPose =
static_cast<unsigned int>(
cMo.size());
488 vpMatrix A(3 * nbPose, 3);
489 vpColVector B(3 * nbPose);
492 for (
unsigned int i = 0;
i < nbPose; ++
i) {
493 for (
unsigned int j = 0;
j < nbPose; ++
j) {
495 vpHomogeneousMatrix ejMei = rMe[
j].inverse() * rMe[
i];
496 vpHomogeneousMatrix cjMci =
cMo[
j] *
cMo[
i].inverse();
498 vpRotationMatrix ejRei, cjRci;
499 vpTranslationVector ejTei, cjTci;
507 vpMatrix a = vpMatrix(ejRei) - I3;
508 vpTranslationVector b = eRc * cjTci - ejTei;
531 vpColVector
x = Ap * B;
532 eTc =
static_cast<vpTranslationVector
>(
x);
536 printf(
"New Hand-eye calibration : ");
537 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
539 vpColVector residual;
540 residual = A *
x - B;
543 printf(
"Mean residual (translation) = %lf\n", res);
562int vpHandEyeCalibration::calibrationTranslationOld(
const std::vector<vpHomogeneousMatrix> &cMo,
573 unsigned int nbPose =
static_cast<unsigned int>(
cMo.size());
575 for (
unsigned int i = 0;
i < nbPose; ++
i) {
576 vpRotationMatrix rRei, ciRo;
577 vpTranslationVector rTei, ciTo;
578 rMe[
i].extract(rRei);
579 cMo[
i].extract(ciRo);
580 rMe[
i].extract(rTei);
581 cMo[
i].extract(ciTo);
583 for (
unsigned int j = 0;
j < nbPose; ++
j) {
585 vpRotationMatrix rRej, cjRo;
586 rMe[
j].extract(rRej);
587 cMo[
j].extract(cjRo);
589 vpTranslationVector rTej, cjTo;
590 rMe[
j].extract(rTej);
591 cMo[
j].extract(cjTo);
593 vpRotationMatrix rReij = rRej.
t() * rRei;
595 vpTranslationVector rTeij = rTej + (-rTei);
597 rTeij = rRej.
t() * rTeij;
599 vpMatrix a = vpMatrix(rReij) - vpMatrix(I3);
601 vpTranslationVector b;
602 b = eRc * cjTo - rReij * eRc * ciTo + rTeij;
619 vpMatrix AtA = A.
AtA();
627 AeTc = Ap * A.
t() * B;
628 eTc =
static_cast<vpTranslationVector
>(AeTc);
632 printf(
"Old Hand-eye calibration : ");
633 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
636 vpColVector residual;
637 residual = A * AeTc - B;
640 for (
unsigned int i = 0;
i < residual.
getRows(); ++
i) {
641 res += residual[
i] * residual[
i];
643 res = sqrt(res / residual.
getRows());
644 printf(
"Mean residual (translation) = %lf\n", res);
661double vpHandEyeCalibration::calibrationErrVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
662 const std::vector<vpHomogeneousMatrix> &rMe,
665 unsigned int nbPose =
static_cast<unsigned int>(
cMo.size());
668 vpRotationMatrix eRc;
669 vpTranslationVector eTc;
674 for (
unsigned int i = 0;
i < nbPose; ++
i) {
675 for (
unsigned int j = 0;
j < nbPose; ++
j) {
679 vpHomogeneousMatrix ejMei = rMe[
j].
inverse() * rMe[
i];
680 vpHomogeneousMatrix cjMci =
cMo[
j] *
cMo[
i].inverse();
682 vpRotationMatrix ejRei, cjRci;
683 vpTranslationVector ejTei, cjTci;
686 vpThetaUVector ejPei(ejRei);
690 vpThetaUVector cjPci(cjRci);
693 s = vpMatrix(eRc) * vpColVector(cjPci) - vpColVector(ejPei);
702 s = (vpMatrix(ejRei) - I3) * eTc - eRc * cjTci + ejTei;
708 double resRot, resTrans, resPos;
709 resRot = resTrans = resPos = 0.0;
710 for (
unsigned int i = 0; i <static_cast<unsigned int>(errVVS.
size());
i += 6) {
711 resRot += errVVS[
i] * errVVS[
i];
712 resRot += errVVS[
i + 1] * errVVS[
i + 1];
713 resRot += errVVS[
i + 2] * errVVS[
i + 2];
714 resTrans += errVVS[
i + 3] * errVVS[
i + 3];
715 resTrans += errVVS[
i + 4] * errVVS[
i + 4];
716 resTrans += errVVS[
i + 5] * errVVS[
i + 5];
718 resPos = resRot + resTrans;
719 resRot = sqrt(resRot * 2 / errVVS.
size());
720 resTrans = sqrt(resTrans * 2 / errVVS.
size());
721 resPos = sqrt(resPos / errVVS.
size());
724 printf(
"Mean VVS residual - rotation (deg) = %lf\n",
vpMath::deg(resRot));
725 printf(
"Mean VVS residual - translation = %lf\n", resTrans);
726 printf(
"Mean VVS residual - global = %lf\n", resPos);
742int vpHandEyeCalibration::calibrationVVS(
const std::vector<vpHomogeneousMatrix> &cMo,
746 unsigned int nb_iter_max = 30;
748 unsigned int nbPose =
static_cast<unsigned int>(
cMo.size());
753 vpRotationMatrix eRc;
754 vpTranslationVector eTc;
763 while ((res > 1e-7) && (it < nb_iter_max)) {
765 vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, err);
768 for (
unsigned int i = 0;
i < nbPose; ++
i) {
769 for (
unsigned int j = 0;
j < nbPose; ++
j) {
772 vpMatrix Ls(3, 6), Lv(3, 3), Lw(3, 3);
774 vpHomogeneousMatrix ejMei = rMe[
j].
inverse() * rMe[
i];
775 vpHomogeneousMatrix cjMci =
cMo[
j] *
cMo[
i].inverse();
777 vpRotationMatrix ejRei;
779 vpThetaUVector cjPci(cjMci);
781 vpTranslationVector cjTci;
788 for (
unsigned int m = 0; m < 3; m++)
789 for (
unsigned int n = 0; n < 3; n++) {
791 Ls[m][n + 3] = Lw[m][n];
801 Lv = (vpMatrix(ejRei) - I3) * vpMatrix(eRc);
803 for (
unsigned int m = 0; m < 3; m++)
804 for (
unsigned int n = 0; n < 3; n++) {
806 Ls[m][n + 3] = Lw[m][n];
815 unsigned int rank = L.pseudoInverse(Lp);
820 vpColVector
e = Lp * err;
821 vpColVector
v = -
e * lambda;
826 res = sqrt(
v.sumSquare() /
v.getRows());
831 printf(
" Iteration number for NL hand-eye minimization : %d\n", it);
832 vpThetaUVector ePc(eRc);
835 std::cout <<
"Translation: " << eTc[0] <<
" " << eTc[1] <<
" " << eTc[2] << std::endl;
838 res = sqrt(res / err.getRows());
839 printf(
"Mean residual (rotation+translation) = %lf\n", res);
842 if (it == nb_iter_max) {
863#define HE_TSAI_OROT 1
864#define HE_TSAI_ORNT 2
865#define HE_TSAI_NROT 3
866#define HE_TSAI_NRNT 4
867#define HE_PROCRUSTES_OT 5
868#define HE_PROCRUSTES_NT 6
872 const std::vector<vpHomogeneousMatrix> &rMe,
875 if (cMo.size() != rMe.size()) {
887 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
888 double vmin = resPos;
890 int He_method = HE_I;
894 int err = vpHandEyeCalibration::calibrationRotationTsaiOld(cMo, rMe, eRc);
896 std::cout <<
"\nProblem in solving Hand-Eye Rotation by Old Tsai method" << std::endl;
900 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
902 std::cout <<
"\nProblem in solving Hand-Eye Translation by Old Tsai method after Old Tsai method for rotation" << std::endl;
908 std::cout <<
"\nRotation by (old) Tsai, old implementation for translation" << std::endl;
909 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
912 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
917 He_method = HE_TSAI_OROT;
921 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
923 std::cout <<
"\n Problem in solving Hand-Eye Translation after Old Tsai method for rotation" << std::endl;
929 std::cout <<
"\nRotation by (old) Tsai, new implementation for translation" << std::endl;
930 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
933 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
938 He_method = HE_TSAI_ORNT;
944 err = vpHandEyeCalibration::calibrationRotationTsai(cMo, rMe, eRc);
946 std::cout <<
"\n Problem in solving Hand-Eye Rotation by Tsai method" << std::endl;
950 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
952 std::cout <<
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Tsai method for rotation" << std::endl;
958 std::cout <<
"\nRotation by Tsai, old implementation for translation" << std::endl;
959 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
962 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
967 He_method = HE_TSAI_NROT;
971 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
973 std::cout <<
"\n Problem in solving Hand-Eye Translation after Tsai method for rotation" << std::endl;
979 std::cout <<
"\nRotation by Tsai, new implementation for translation" << std::endl;
980 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
983 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
988 He_method = HE_TSAI_NRNT;
994 err = vpHandEyeCalibration::calibrationRotationProcrustes(cMo, rMe, eRc);
996 std::cout <<
"\n Problem in solving Hand-Eye Rotation by Procrustes method" << std::endl;
999 err = vpHandEyeCalibration::calibrationTranslationOld(cMo, rMe, eRc, eTc);
1001 std::cout <<
"\n Problem in solving Hand-Eye Translation by Old Tsai method after Procrustes method for rotation" << std::endl;
1007 std::cout <<
"\nRotation by Procrustes, old implementation for translation" << std::endl;
1008 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
1011 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
1012 if (resPos < vmin) {
1016 He_method = HE_PROCRUSTES_OT;
1020 err = vpHandEyeCalibration::calibrationTranslation(cMo, rMe, eRc, eTc);
1022 std::cout <<
"\n Problem in solving Hand-Eye Translation after Procrustes method for rotation" << std::endl;
1028 std::cout <<
"\nRotation by Procrustes, new implementation for translation" << std::endl;
1029 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc);
1032 resPos = vpHandEyeCalibration::calibrationErrVVS(cMo, rMe, eMc, errVVS);
1033 if (resPos < vmin) {
1037 He_method = HE_PROCRUSTES_NT;
1047 if (He_method == HE_I) {
1048 std::cout <<
"Best method : I !!!, vmin = " << vmin << std::endl;
1050 if (He_method == HE_TSAI_OROT) {
1051 std::cout <<
"Best method : TSAI_OROT, vmin = " << vmin << std::endl;
1053 if (He_method == HE_TSAI_ORNT) {
1054 std::cout <<
"Best method : TSAI_ORNT, vmin = " << vmin << std::endl;
1056 if (He_method == HE_TSAI_NROT) {
1057 std::cout <<
"Best method : TSAI_NROT, vmin = " << vmin << std::endl;
1059 if (He_method == HE_TSAI_NRNT) {
1060 std::cout <<
"Best method : TSAI_NRNT, vmin = " << vmin << std::endl;
1062 if (He_method == HE_PROCRUSTES_OT) {
1063 std::cout <<
"Best method : PROCRUSTES_OT, vmin = " << vmin << std::endl;
1065 if (He_method == HE_PROCRUSTES_NT) {
1066 std::cout <<
"Best method : PROCRUSTES_NT, vmin = " << vmin << std::endl;
1071 std::cout <<
"Translation: " << eMc[0][3] <<
" " << eMc[1][3] <<
" " << eMc[2][3] << std::endl;
1076 err = vpHandEyeCalibration::calibrationVVS(cMo, rMe, eMc);
1079 std::cout <<
"\n Problem in solving Hand-Eye Calibration by VVS" << std::endl;
1083 vpHandEyeCalibration::calibrationVerifrMo(cMo, rMe, eMc, rMo);
1093#undef HE_PROCRUSTES_OT
1094#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)
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)