Skip to content

Commit

Permalink
Implement point cloud alignment for SE3
Browse files Browse the repository at this point in the history
This is equivalent to `Eigen::umeyama` but faster and stores the results
more compactly.
  • Loading branch information
Hs293Go committed Apr 4, 2022
1 parent 0f7f957 commit ecd252a
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
47 changes: 47 additions & 0 deletions sophus/se3.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,53 @@ class SE3 : public SE3Base<SE3<Scalar_, Options>> {
return upsilon_omega;
}

template <typename Derived, typename OtherDerived>
SOPHUS_FUNC void setFromPointClouds(
Eigen::MatrixBase<Derived> const& src,
Eigen::MatrixBase<OtherDerived> const& dst) {
using Eigen::Index;
using MatrixType =
typename Eigen::internal::plain_matrix_type<Derived>::type;
const Index N = src.cols();

SOPHUS_ENSURE(
src.rows() == 3 && dst.rows() == 3 && N == dst.cols(),
"Point clouds are stored in 3xN matrices, one point per column. Source "
"and destination matrices are {}x{} and {}x{} respectively",
src.rows(), N, dst.rows(), dst.cols());

Scalar w(1. / N);
Vector3<Scalar> const src_mean = src.rowwise().sum() * w;
Vector3<Scalar> const dst_mean = dst.rowwise().sum() * w;

MatrixType m1 = src.colwise() - src_mean;
MatrixType m2 = dst.colwise() - dst_mean;

m1 += m2;
m2 = m1 - Scalar(2) * m2;
Matrix4<Scalar> W = Matrix4<Scalar>::Zero();
for (Index i(0); i < N; ++i) {
Matrix3<Scalar> const S = SO3<Scalar>::hat(m1.col(i));
Vector3<Scalar> const v = m2.col(i);
Matrix4<Scalar> V;
V << S, -v, v.transpose(), Scalar(0);
W += w * V.transpose() * V;
}
const Eigen::SelfAdjointEigenSolver<Matrix4<Scalar>> eig(W);
const Eigen::Quaternion<Scalar> rotation(eig.eigenvectors().real().col(0));
so3_.setQuaternion(rotation);
translation_ = dst_mean - rotation * src_mean;
}

template <typename Derived, typename OtherDerived>
SOPHUS_FUNC static SE3<Scalar> FromPointClouds(
Eigen::MatrixBase<Derived> const& src,
Eigen::MatrixBase<OtherDerived> const& dst) {
SE3<Scalar> ret;
ret.setFromPointClouds(src, dst);
return ret;
}

protected:
SO3Member so3_;
TranslationMember translation_;
Expand Down
44 changes: 44 additions & 0 deletions test/core/test_se3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Tests {
passed &= testMutatingAccessors();
passed &= testConstructors();
passed &= testFit();
passed &= testPointCloudAlignment();
processTestResult(passed);
}

Expand Down Expand Up @@ -243,6 +244,49 @@ class Tests {
return true;
}

template <class S = Scalar>
enable_if_t<std::is_floating_point<S>::value, bool>
testPointCloudAlignment() {
bool passed = true;

using MatrixType = Eigen::Matrix<S, 3, Eigen::Dynamic>;

const int sz = point_vec_.size();
Eigen::Map<const MatrixType> src(point_vec_.front().data(), 3, sz);
MatrixType dst(3, sz);

for (const auto& it : se3_vec_) {
for (int i = 0; i < sz; ++i) {
dst.col(i) = it * src.col(i);
}
SE3Type result;
result.setFromPointClouds(src, dst);
SOPHUS_TEST_APPROX(passed, it.translation(), result.translation(),
Constants<Scalar>::epsilon(),
"Expected translation: {}; Got: {}", it.translation(),
result.translation());
SOPHUS_TEST_APPROX(
passed, it.matrix(), result.matrix(), Constants<Scalar>::epsilon(),
"Expected rotation: {}; Got: {}", it.matrix(), result.matrix());

result = SE3Type::FromPointClouds(src, dst);
SOPHUS_TEST_APPROX(passed, it.translation(), result.translation(),
Constants<Scalar>::epsilon(),
"Expected translation: {}; Got: {}", it.translation(),
result.translation());
SOPHUS_TEST_APPROX(
passed, it.matrix(), result.matrix(), Constants<Scalar>::epsilon(),
"Expected rotation: {}; Got: {}", it.matrix(), result.matrix());
}
return passed;
}

template <class S = Scalar>
enable_if_t<!std::is_floating_point<S>::value, bool>
testPointCloudAlignment() {
return true;
}

std::vector<SE3Type, Eigen::aligned_allocator<SE3Type>> se3_vec_;
std::vector<Tangent, Eigen::aligned_allocator<Tangent>> tangent_vec_;
std::vector<Point, Eigen::aligned_allocator<Point>> point_vec_;
Expand Down

0 comments on commit ecd252a

Please sign in to comment.