procrustes.cpp 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "procrustes.h"
  9. template <typename DerivedV, typename Scalar, int DIM, int TType>
  10. IGL_INLINE void igl::procrustes(
  11. const Eigen::PlainObjectBase<DerivedV>& X,
  12. const Eigen::PlainObjectBase<DerivedV>& Y,
  13. bool includeScaling,
  14. bool includeReflections,
  15. Eigen::Transform<Scalar,DIM,TType>& T)
  16. {
  17. using namespace Eigen;
  18. assert (X.rows() == Y.rows() && "Same number of points");
  19. assert(X.cols() == Y.cols() && "Points have same dimensions");
  20. // Center data
  21. VectorXd Xmean = X.colwise().mean();
  22. VectorXd Ymean = Y.colwise().mean();
  23. MatrixXd XC = X.rowwise() - Xmean.transpose();
  24. MatrixXd YC = Y.rowwise() - Ymean.transpose();
  25. // Determine scale
  26. double scale = 1.;
  27. if (includeScaling)
  28. {
  29. double scaleX = XC.norm() / XC.rows();
  30. double scaleY = YC.norm() / YC.rows();
  31. scale = scaleY/scaleX;
  32. XC *= scale;
  33. assert (abs(XC.norm() / XC.rows() - scaleY) < 1e-8);
  34. }
  35. // Rotation
  36. MatrixXd M = XC.transpose() * YC;
  37. JacobiSVD<Eigen::MatrixXd> svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
  38. MatrixXd sigma;
  39. sigma.setIdentity(DIM,DIM);
  40. if (!includeReflections && (svd.matrixU() * svd.matrixV().transpose()).determinant() < 0)
  41. sigma(DIM-1,DIM-1) = -1.;
  42. Matrix<Scalar,DIM,DIM> R = svd.matrixU() * sigma * svd.matrixV().transpose();
  43. assert(abs(R.determinant() - 1) < 1e-10);
  44. // Translation
  45. Matrix<Scalar,DIM,1> t = Ymean - scale*R*Xmean;
  46. // Combine
  47. T = Translation<Scalar,DIM>(t) * R.transpose() * Scaling(scale);
  48. }