123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /// @file
- /// Calculation of biinvariant means.
- #ifndef SOPHUS_AVERAGE_HPP
- #define SOPHUS_AVERAGE_HPP
- #include "common.hpp"
- #include "rxso2.hpp"
- #include "rxso3.hpp"
- #include "se2.hpp"
- #include "se3.hpp"
- #include "sim2.hpp"
- #include "sim3.hpp"
- #include "so2.hpp"
- #include "so3.hpp"
- namespace Sophus {
- /// Calculates mean iteratively.
- ///
- /// Returns ``nullopt`` if it does not converge.
- ///
- template <class SequenceContainer>
- optional<typename SequenceContainer::value_type> iterativeMean(
- SequenceContainer const& foo_Ts_bar, int max_num_iterations) {
- size_t N = foo_Ts_bar.size();
- SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
- using Group = typename SequenceContainer::value_type;
- using Scalar = typename Group::Scalar;
- using Tangent = typename Group::Tangent;
- // This implements the algorithm in the beginning of Sec. 4.2 in
- // ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
- Group foo_T_average = foo_Ts_bar.front();
- Scalar w = Scalar(1. / N);
- for (int i = 0; i < max_num_iterations; ++i) {
- Tangent average;
- setToZero<Tangent>(average);
- for (Group const& foo_T_bar : foo_Ts_bar) {
- average += w * (foo_T_average.inverse() * foo_T_bar).log();
- }
- Group foo_T_newaverage = foo_T_average * Group::exp(average);
- if (squaredNorm<Tangent>(
- (foo_T_newaverage.inverse() * foo_T_average).log()) <
- Constants<Scalar>::epsilon()) {
- return foo_T_newaverage;
- }
- foo_T_average = foo_T_newaverage;
- }
- // LCOV_EXCL_START
- return nullopt;
- // LCOV_EXCL_STOP
- }
- #ifdef DOXYGEN_SHOULD_SKIP_THIS
- /// Mean implementation for any Lie group.
- template <class SequenceContainer, class Scalar>
- optional<typename SequenceContainer::value_type> average(
- SequenceContainer const& foo_Ts_bar);
- #else
- // Mean implementation for SO(2).
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, SO2<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar) {
- // This implements rotational part of Proposition 12 from Sec. 6.2 of
- // ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
- size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
- SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
- SO2<Scalar> foo_T_average = foo_Ts_bar.front();
- Scalar w = Scalar(1. / N);
- Scalar average(0);
- for (SO2<Scalar> const& foo_T_bar : foo_Ts_bar) {
- average += w * (foo_T_average.inverse() * foo_T_bar).log();
- }
- return foo_T_average * SO2<Scalar>::exp(average);
- }
- // Mean implementation for RxSO(2).
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, RxSO2<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar) {
- size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
- SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
- RxSO2<Scalar> foo_T_average = foo_Ts_bar.front();
- Scalar w = Scalar(1. / N);
- Vector2<Scalar> average(Scalar(0), Scalar(0));
- for (RxSO2<Scalar> const& foo_T_bar : foo_Ts_bar) {
- average += w * (foo_T_average.inverse() * foo_T_bar).log();
- }
- return foo_T_average * RxSO2<Scalar>::exp(average);
- }
- namespace details {
- template <class T>
- void getQuaternion(T const&);
- template <class Scalar>
- Eigen::Quaternion<Scalar> getUnitQuaternion(SO3<Scalar> const& R) {
- return R.unit_quaternion();
- }
- template <class Scalar>
- Eigen::Quaternion<Scalar> getUnitQuaternion(RxSO3<Scalar> const& sR) {
- return sR.so3().unit_quaternion();
- }
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- Eigen::Quaternion<Scalar> averageUnitQuaternion(
- SequenceContainer const& foo_Ts_bar) {
- // This: http://stackoverflow.com/a/27410865/1221742
- size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
- SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
- Eigen::Matrix<Scalar, 4, Eigen::Dynamic> Q(4, N);
- int i = 0;
- Scalar w = Scalar(1. / N);
- for (auto const& foo_T_bar : foo_Ts_bar) {
- Q.col(i) = w * details::getUnitQuaternion(foo_T_bar).coeffs();
- ++i;
- }
- Eigen::Matrix<Scalar, 4, 4> QQt = Q * Q.transpose();
- // TODO: Figure out why we can't use SelfAdjointEigenSolver here.
- Eigen::EigenSolver<Eigen::Matrix<Scalar, 4, 4> > es(QQt);
- std::complex<Scalar> max_eigenvalue = es.eigenvalues()[0];
- Eigen::Matrix<std::complex<Scalar>, 4, 1> max_eigenvector =
- es.eigenvectors().col(0);
- for (int i = 1; i < 4; i++) {
- if (std::norm(es.eigenvalues()[i]) > std::norm(max_eigenvalue)) {
- max_eigenvalue = es.eigenvalues()[i];
- max_eigenvector = es.eigenvectors().col(i);
- }
- }
- Eigen::Quaternion<Scalar> quat;
- quat.coeffs() << //
- max_eigenvector[0].real(), //
- max_eigenvector[1].real(), //
- max_eigenvector[2].real(), //
- max_eigenvector[3].real();
- return quat;
- }
- } // namespace details
- // Mean implementation for SO(3).
- //
- // TODO: Detect degenerated cases and return nullopt.
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, SO3<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar) {
- return SO3<Scalar>(details::averageUnitQuaternion(foo_Ts_bar));
- }
- // Mean implementation for R x SO(3).
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, RxSO3<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar) {
- size_t N = std::distance(std::begin(foo_Ts_bar), std::end(foo_Ts_bar));
- SOPHUS_ENSURE(N >= 1, "N must be >= 1.");
- Scalar scale_sum = Scalar(0);
- using std::exp;
- using std::log;
- for (RxSO3<Scalar> const& foo_T_bar : foo_Ts_bar) {
- scale_sum += log(foo_T_bar.scale());
- }
- return RxSO3<Scalar>(exp(scale_sum / Scalar(N)),
- SO3<Scalar>(details::averageUnitQuaternion(foo_Ts_bar)));
- }
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, SE2<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
- // TODO: Implement Proposition 12 from Sec. 6.2 of
- // ftp://ftp-sop.inria.fr/epidaure/Publications/Arsigny/arsigny_rr_biinvariant_average.pdf.
- return iterativeMean(foo_Ts_bar, max_num_iterations);
- }
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, Sim2<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
- return iterativeMean(foo_Ts_bar, max_num_iterations);
- }
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, SE3<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
- return iterativeMean(foo_Ts_bar, max_num_iterations);
- }
- template <class SequenceContainer,
- class Scalar = typename SequenceContainer::value_type::Scalar>
- enable_if_t<
- std::is_same<typename SequenceContainer::value_type, Sim3<Scalar> >::value,
- optional<typename SequenceContainer::value_type> >
- average(SequenceContainer const& foo_Ts_bar, int max_num_iterations = 20) {
- return iterativeMean(foo_Ts_bar, max_num_iterations);
- }
- #endif // DOXYGEN_SHOULD_SKIP_THIS
- } // namespace Sophus
- #endif // SOPHUS_AVERAGE_HPP
|