Umeyama.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2009 Hauke Heibel <hauke.heibel@gmail.com>
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla
  7. // Public License v. 2.0. If a copy of the MPL was not distributed
  8. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. #ifndef EIGEN_UMEYAMA_H
  10. #define EIGEN_UMEYAMA_H
  11. // This file requires the user to include
  12. // * Eigen/Core
  13. // * Eigen/LU
  14. // * Eigen/SVD
  15. // * Eigen/Array
  16. namespace Eigen {
  17. #ifndef EIGEN_PARSED_BY_DOXYGEN
  18. // These helpers are required since it allows to use mixed types as parameters
  19. // for the Umeyama. The problem with mixed parameters is that the return type
  20. // cannot trivially be deduced when float and double types are mixed.
  21. namespace internal {
  22. // Compile time return type deduction for different MatrixBase types.
  23. // Different means here different alignment and parameters but the same underlying
  24. // real scalar type.
  25. template<typename MatrixType, typename OtherMatrixType>
  26. struct umeyama_transform_matrix_type
  27. {
  28. enum {
  29. MinRowsAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(MatrixType::RowsAtCompileTime, OtherMatrixType::RowsAtCompileTime),
  30. // When possible we want to choose some small fixed size value since the result
  31. // is likely to fit on the stack. So here, EIGEN_SIZE_MIN_PREFER_DYNAMIC is not what we want.
  32. HomogeneousDimension = int(MinRowsAtCompileTime) == Dynamic ? Dynamic : int(MinRowsAtCompileTime)+1
  33. };
  34. typedef Matrix<typename traits<MatrixType>::Scalar,
  35. HomogeneousDimension,
  36. HomogeneousDimension,
  37. AutoAlign | (traits<MatrixType>::Flags & RowMajorBit ? RowMajor : ColMajor),
  38. HomogeneousDimension,
  39. HomogeneousDimension
  40. > type;
  41. };
  42. }
  43. #endif
  44. /**
  45. * \geometry_module \ingroup Geometry_Module
  46. *
  47. * \brief Returns the transformation between two point sets.
  48. *
  49. * The algorithm is based on:
  50. * "Least-squares estimation of transformation parameters between two point patterns",
  51. * Shinji Umeyama, PAMI 1991, DOI: 10.1109/34.88573
  52. *
  53. * It estimates parameters \f$ c, \mathbf{R}, \f$ and \f$ \mathbf{t} \f$ such that
  54. * \f{align*}
  55. * \frac{1}{n} \sum_{i=1}^n \vert\vert y_i - (c\mathbf{R}x_i + \mathbf{t}) \vert\vert_2^2
  56. * \f}
  57. * is minimized.
  58. *
  59. * The algorithm is based on the analysis of the covariance matrix
  60. * \f$ \Sigma_{\mathbf{x}\mathbf{y}} \in \mathbb{R}^{d \times d} \f$
  61. * of the input point sets \f$ \mathbf{x} \f$ and \f$ \mathbf{y} \f$ where
  62. * \f$d\f$ is corresponding to the dimension (which is typically small).
  63. * The analysis is involving the SVD having a complexity of \f$O(d^3)\f$
  64. * though the actual computational effort lies in the covariance
  65. * matrix computation which has an asymptotic lower bound of \f$O(dm)\f$ when
  66. * the input point sets have dimension \f$d \times m\f$.
  67. *
  68. * Currently the method is working only for floating point matrices.
  69. *
  70. * \todo Should the return type of umeyama() become a Transform?
  71. *
  72. * \param src Source points \f$ \mathbf{x} = \left( x_1, \hdots, x_n \right) \f$.
  73. * \param dst Destination points \f$ \mathbf{y} = \left( y_1, \hdots, y_n \right) \f$.
  74. * \param with_scaling Sets \f$ c=1 \f$ when <code>false</code> is passed.
  75. * \return The homogeneous transformation
  76. * \f{align*}
  77. * T = \begin{bmatrix} c\mathbf{R} & \mathbf{t} \\ \mathbf{0} & 1 \end{bmatrix}
  78. * \f}
  79. * minimizing the residual above. This transformation is always returned as an
  80. * Eigen::Matrix.
  81. */
  82. template <typename Derived, typename OtherDerived>
  83. typename internal::umeyama_transform_matrix_type<Derived, OtherDerived>::type
  84. umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, bool with_scaling = true)
  85. {
  86. typedef typename internal::umeyama_transform_matrix_type<Derived, OtherDerived>::type TransformationMatrixType;
  87. typedef typename internal::traits<TransformationMatrixType>::Scalar Scalar;
  88. typedef typename NumTraits<Scalar>::Real RealScalar;
  89. EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
  90. EIGEN_STATIC_ASSERT((internal::is_same<Scalar, typename internal::traits<OtherDerived>::Scalar>::value),
  91. YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
  92. enum { Dimension = EIGEN_SIZE_MIN_PREFER_DYNAMIC(Derived::RowsAtCompileTime, OtherDerived::RowsAtCompileTime) };
  93. typedef Matrix<Scalar, Dimension, 1> VectorType;
  94. typedef Matrix<Scalar, Dimension, Dimension> MatrixType;
  95. typedef typename internal::plain_matrix_type_row_major<Derived>::type RowMajorMatrixType;
  96. const Index m = src.rows(); // dimension
  97. const Index n = src.cols(); // number of measurements
  98. // required for demeaning ...
  99. const RealScalar one_over_n = RealScalar(1) / static_cast<RealScalar>(n);
  100. // computation of mean
  101. const VectorType src_mean = src.rowwise().sum() * one_over_n;
  102. const VectorType dst_mean = dst.rowwise().sum() * one_over_n;
  103. // demeaning of src and dst points
  104. const RowMajorMatrixType src_demean = src.colwise() - src_mean;
  105. const RowMajorMatrixType dst_demean = dst.colwise() - dst_mean;
  106. // Eq. (36)-(37)
  107. const Scalar src_var = src_demean.rowwise().squaredNorm().sum() * one_over_n;
  108. // Eq. (38)
  109. const MatrixType sigma = one_over_n * dst_demean * src_demean.transpose();
  110. JacobiSVD<MatrixType> svd(sigma, ComputeFullU | ComputeFullV);
  111. // Initialize the resulting transformation with an identity matrix...
  112. TransformationMatrixType Rt = TransformationMatrixType::Identity(m+1,m+1);
  113. // Eq. (39)
  114. VectorType S = VectorType::Ones(m);
  115. if ( svd.matrixU().determinant() * svd.matrixV().determinant() < 0 )
  116. S(m-1) = -1;
  117. // Eq. (40) and (43)
  118. Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose();
  119. if (with_scaling)
  120. {
  121. // Eq. (42)
  122. const Scalar c = Scalar(1)/src_var * svd.singularValues().dot(S);
  123. // Eq. (41)
  124. Rt.col(m).head(m) = dst_mean;
  125. Rt.col(m).head(m).noalias() -= c*Rt.topLeftCorner(m,m)*src_mean;
  126. Rt.block(0,0,m,m) *= c;
  127. }
  128. else
  129. {
  130. Rt.col(m).head(m) = dst_mean;
  131. Rt.col(m).head(m).noalias() -= Rt.topLeftCorner(m,m)*src_mean;
  132. }
  133. return Rt;
  134. }
  135. } // end namespace Eigen
  136. #endif // EIGEN_UMEYAMA_H