-
Notifications
You must be signed in to change notification settings - Fork 789
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #918 from borglab/add-Similarity2-classes
- Loading branch information
Showing
18 changed files
with
855 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
/* ---------------------------------------------------------------------------- | ||
* GTSAM Copyright 2010, Georgia Tech Research Corporation, | ||
* Atlanta, Georgia 30332-0415 | ||
* All Rights Reserved | ||
* Authors: Frank Dellaert, et al. (see THANKS for the full author list) | ||
* See LICENSE for the license information | ||
* -------------------------------------------------------------------------- */ | ||
|
||
/** | ||
* @file Similarity2.cpp | ||
* @brief Implementation of Similarity2 transform | ||
* @author John Lambert, Varun Agrawal | ||
*/ | ||
|
||
#include <gtsam/base/Manifold.h> | ||
#include <gtsam/geometry/Pose2.h> | ||
#include <gtsam/geometry/Rot3.h> | ||
#include <gtsam/geometry/Similarity2.h> | ||
#include <gtsam/slam/KarcherMeanFactor-inl.h> | ||
|
||
namespace gtsam { | ||
|
||
using std::vector; | ||
|
||
namespace internal { | ||
|
||
/// Subtract centroids from point pairs. | ||
static Point2Pairs SubtractCentroids(const Point2Pairs& abPointPairs, | ||
const Point2Pair& centroids) { | ||
Point2Pairs d_abPointPairs; | ||
for (const Point2Pair& abPair : abPointPairs) { | ||
Point2 da = abPair.first - centroids.first; | ||
Point2 db = abPair.second - centroids.second; | ||
d_abPointPairs.emplace_back(da, db); | ||
} | ||
return d_abPointPairs; | ||
} | ||
|
||
/// Form inner products x and y and calculate scale. | ||
static double CalculateScale(const Point2Pairs& d_abPointPairs, | ||
const Rot2& aRb) { | ||
double x = 0, y = 0; | ||
Point2 da, db; | ||
|
||
for (const Point2Pair& d_abPair : d_abPointPairs) { | ||
std::tie(da, db) = d_abPair; | ||
const Vector2 da_prime = aRb * db; | ||
y += da.transpose() * da_prime; | ||
x += da_prime.transpose() * da_prime; | ||
} | ||
const double s = y / x; | ||
return s; | ||
} | ||
|
||
/// Form outer product H. | ||
static Matrix2 CalculateH(const Point2Pairs& d_abPointPairs) { | ||
Matrix2 H = Z_2x2; | ||
for (const Point2Pair& d_abPair : d_abPointPairs) { | ||
H += d_abPair.first * d_abPair.second.transpose(); | ||
} | ||
return H; | ||
} | ||
|
||
/** | ||
* @brief This method estimates the similarity transform from differences point | ||
* pairs, given a known or estimated rotation and point centroids. | ||
* | ||
* @param d_abPointPairs | ||
* @param aRb | ||
* @param centroids | ||
* @return Similarity2 | ||
*/ | ||
static Similarity2 Align(const Point2Pairs& d_abPointPairs, const Rot2& aRb, | ||
const Point2Pair& centroids) { | ||
const double s = CalculateScale(d_abPointPairs, aRb); | ||
// dividing aTb by s is required because the registration cost function | ||
// minimizes ||a - sRb - t||, whereas Sim(2) computes s(Rb + t) | ||
const Point2 aTb = (centroids.first - s * (aRb * centroids.second)) / s; | ||
return Similarity2(aRb, aTb, s); | ||
} | ||
|
||
/** | ||
* @brief This method estimates the similarity transform from point pairs, | ||
* given a known or estimated rotation. | ||
* Refer to: | ||
* http://www5.informatik.uni-erlangen.de/Forschung/Publikationen/2005/Zinsser05-PSR.pdf | ||
* Chapter 3 | ||
* | ||
* @param abPointPairs | ||
* @param aRb | ||
* @return Similarity2 | ||
*/ | ||
static Similarity2 AlignGivenR(const Point2Pairs& abPointPairs, | ||
const Rot2& aRb) { | ||
auto centroids = means(abPointPairs); | ||
auto d_abPointPairs = internal::SubtractCentroids(abPointPairs, centroids); | ||
return internal::Align(d_abPointPairs, aRb, centroids); | ||
} | ||
} // namespace internal | ||
|
||
Similarity2::Similarity2() : t_(0, 0), s_(1) {} | ||
|
||
Similarity2::Similarity2(double s) : t_(0, 0), s_(s) {} | ||
|
||
Similarity2::Similarity2(const Rot2& R, const Point2& t, double s) | ||
: R_(R), t_(t), s_(s) {} | ||
|
||
Similarity2::Similarity2(const Matrix2& R, const Vector2& t, double s) | ||
: R_(Rot2::ClosestTo(R)), t_(t), s_(s) {} | ||
|
||
Similarity2::Similarity2(const Matrix3& T) | ||
: R_(Rot2::ClosestTo(T.topLeftCorner<2, 2>())), | ||
t_(T.topRightCorner<2, 1>()), | ||
s_(1.0 / T(2, 2)) {} | ||
|
||
bool Similarity2::equals(const Similarity2& other, double tol) const { | ||
return R_.equals(other.R_, tol) && | ||
traits<Point2>::Equals(t_, other.t_, tol) && s_ < (other.s_ + tol) && | ||
s_ > (other.s_ - tol); | ||
} | ||
|
||
bool Similarity2::operator==(const Similarity2& other) const { | ||
return R_.matrix() == other.R_.matrix() && t_ == other.t_ && s_ == other.s_; | ||
} | ||
|
||
void Similarity2::print(const std::string& s) const { | ||
std::cout << std::endl; | ||
std::cout << s; | ||
rotation().print("\nR:\n"); | ||
std::cout << "t: " << translation().transpose() << " s: " << scale() | ||
<< std::endl; | ||
} | ||
|
||
Similarity2 Similarity2::identity() { return Similarity2(); } | ||
|
||
Similarity2 Similarity2::operator*(const Similarity2& S) const { | ||
return Similarity2(R_ * S.R_, ((1.0 / S.s_) * t_) + R_ * S.t_, s_ * S.s_); | ||
} | ||
|
||
Similarity2 Similarity2::inverse() const { | ||
const Rot2 Rt = R_.inverse(); | ||
const Point2 sRt = Rt * (-s_ * t_); | ||
return Similarity2(Rt, sRt, 1.0 / s_); | ||
} | ||
|
||
Point2 Similarity2::transformFrom(const Point2& p) const { | ||
const Point2 q = R_ * p + t_; | ||
return s_ * q; | ||
} | ||
|
||
Pose2 Similarity2::transformFrom(const Pose2& T) const { | ||
Rot2 R = R_.compose(T.rotation()); | ||
Point2 t = Point2(s_ * (R_ * T.translation() + t_)); | ||
return Pose2(R, t); | ||
} | ||
|
||
Point2 Similarity2::operator*(const Point2& p) const { | ||
return transformFrom(p); | ||
} | ||
|
||
Similarity2 Similarity2::Align(const Point2Pairs& abPointPairs) { | ||
// Refer to Chapter 3 of | ||
// http://www5.informatik.uni-erlangen.de/Forschung/Publikationen/2005/Zinsser05-PSR.pdf | ||
if (abPointPairs.size() < 2) | ||
throw std::runtime_error("input should have at least 2 pairs of points"); | ||
auto centroids = means(abPointPairs); | ||
auto d_abPointPairs = internal::SubtractCentroids(abPointPairs, centroids); | ||
Matrix2 H = internal::CalculateH(d_abPointPairs); | ||
// ClosestTo finds rotation matrix closest to H in Frobenius sense | ||
Rot2 aRb = Rot2::ClosestTo(H); | ||
return internal::Align(d_abPointPairs, aRb, centroids); | ||
} | ||
|
||
Similarity2 Similarity2::Align(const Pose2Pairs& abPosePairs) { | ||
const size_t n = abPosePairs.size(); | ||
if (n < 2) | ||
throw std::runtime_error("input should have at least 2 pairs of poses"); | ||
|
||
// calculate rotation | ||
vector<Rot2> rotations; | ||
Point2Pairs abPointPairs; | ||
rotations.reserve(n); | ||
abPointPairs.reserve(n); | ||
// Below denotes the pose of the i'th object/camera/etc | ||
// in frame "a" or frame "b". | ||
Pose2 aTi, bTi; | ||
for (const Pose2Pair& abPair : abPosePairs) { | ||
std::tie(aTi, bTi) = abPair; | ||
const Rot2 aRb = aTi.rotation().compose(bTi.rotation().inverse()); | ||
rotations.emplace_back(aRb); | ||
abPointPairs.emplace_back(aTi.translation(), bTi.translation()); | ||
} | ||
const Rot2 aRb_estimate = FindKarcherMean<Rot2>(rotations); | ||
|
||
return internal::AlignGivenR(abPointPairs, aRb_estimate); | ||
} | ||
|
||
Vector4 Similarity2::Logmap(const Similarity2& S, // | ||
OptionalJacobian<4, 4> Hm) { | ||
const Vector2 u = S.t_; | ||
const Vector1 w = Rot2::Logmap(S.R_); | ||
const double s = log(S.s_); | ||
Vector4 result; | ||
result << u, w, s; | ||
if (Hm) { | ||
throw std::runtime_error("Similarity2::Logmap: derivative not implemented"); | ||
} | ||
return result; | ||
} | ||
|
||
Similarity2 Similarity2::Expmap(const Vector4& v, // | ||
OptionalJacobian<4, 4> Hm) { | ||
const Vector2 t = v.head<2>(); | ||
const Rot2 R = Rot2::Expmap(v.segment<1>(2)); | ||
const double s = v[3]; | ||
if (Hm) { | ||
throw std::runtime_error("Similarity2::Expmap: derivative not implemented"); | ||
} | ||
return Similarity2(R, t, s); | ||
} | ||
|
||
Matrix4 Similarity2::AdjointMap() const { | ||
throw std::runtime_error("Similarity2::AdjointMap not implemented"); | ||
} | ||
|
||
std::ostream& operator<<(std::ostream& os, const Similarity2& p) { | ||
os << "[" << p.rotation().theta() << " " << p.translation().transpose() << " " | ||
<< p.scale() << "]\';"; | ||
return os; | ||
} | ||
|
||
Matrix3 Similarity2::matrix() const { | ||
Matrix3 T; | ||
T.topRows<2>() << R_.matrix(), t_; | ||
T.bottomRows<1>() << 0, 0, 1.0 / s_; | ||
return T; | ||
} | ||
|
||
} // namespace gtsam |
Oops, something went wrong.