Successful representation of E as product manifold
parent
387dfe5229
commit
994196d37d
|
|
@ -13,64 +13,46 @@ using namespace std;
|
||||||
namespace gtsam {
|
namespace gtsam {
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
EssentialMatrix EssentialMatrix::FromPose3(const Pose3& _1P2_,
|
EssentialMatrix EssentialMatrix::FromPose3(const Pose3& aPb,
|
||||||
OptionalJacobian<5, 6> H) {
|
OptionalJacobian<5, 6> H) {
|
||||||
const Rot3& _1R2_ = _1P2_.rotation();
|
const Rot3& aRb = aPb.rotation();
|
||||||
const Point3& _1T2_ = _1P2_.translation();
|
const Point3& aTb = aPb.translation();
|
||||||
if (!H) {
|
if (!H) {
|
||||||
// just make a direction out of translation and create E
|
// just make a direction out of translation and create E
|
||||||
Unit3 direction(_1T2_);
|
Unit3 direction(aTb);
|
||||||
return EssentialMatrix(_1R2_, direction);
|
return EssentialMatrix(aRb, direction);
|
||||||
} else {
|
} else {
|
||||||
// Calculate the 5*6 Jacobian H = D_E_1P2
|
// Calculate the 5*6 Jacobian H = D_E_1P2
|
||||||
// D_E_1P2 = [D_E_1R2 D_E_1T2], 5*3 wrpt rotation, 5*3 wrpt translation
|
// D_E_1P2 = [D_E_1R2 D_E_1T2], 5*3 wrpt rotation, 5*3 wrpt translation
|
||||||
// First get 2*3 derivative from Unit3::FromPoint3
|
// First get 2*3 derivative from Unit3::FromPoint3
|
||||||
Matrix23 D_direction_1T2;
|
Matrix23 D_direction_1T2;
|
||||||
Unit3 direction = Unit3::FromPoint3(_1T2_, D_direction_1T2);
|
Unit3 direction = Unit3::FromPoint3(aTb, D_direction_1T2);
|
||||||
*H << I_3x3, Z_3x3, //
|
*H << I_3x3, Z_3x3, //
|
||||||
Matrix23::Zero(), D_direction_1T2 * _1R2_.matrix();
|
Matrix23::Zero(), D_direction_1T2 * aRb.matrix();
|
||||||
return EssentialMatrix(_1R2_, direction);
|
return EssentialMatrix(aRb, direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
void EssentialMatrix::print(const string& s) const {
|
void EssentialMatrix::print(const string& s) const {
|
||||||
cout << s;
|
cout << s;
|
||||||
aRb_.print("R:\n");
|
rotation().print("R:\n");
|
||||||
aTb_.print("d: ");
|
direction().print("d: ");
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************************************************* */
|
|
||||||
EssentialMatrix EssentialMatrix::retract(const Vector& xi) const {
|
|
||||||
assert(xi.size() == 5);
|
|
||||||
Vector3 omega(sub(xi, 0, 3));
|
|
||||||
Vector2 z(sub(xi, 3, 5));
|
|
||||||
Rot3 R = aRb_.retract(omega);
|
|
||||||
Unit3 t = aTb_.retract(z);
|
|
||||||
return EssentialMatrix(R, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************************************************* */
|
|
||||||
Vector5 EssentialMatrix::localCoordinates(const EssentialMatrix& other) const {
|
|
||||||
Vector5 v;
|
|
||||||
v << aRb_.localCoordinates(other.aRb_),
|
|
||||||
aTb_.localCoordinates(other.aTb_);
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
Point3 EssentialMatrix::transform_to(const Point3& p, OptionalJacobian<3, 5> DE,
|
Point3 EssentialMatrix::transform_to(const Point3& p, OptionalJacobian<3, 5> DE,
|
||||||
OptionalJacobian<3, 3> Dpoint) const {
|
OptionalJacobian<3, 3> Dpoint) const {
|
||||||
Pose3 pose(aRb_, aTb_.point3());
|
Pose3 pose(rotation(), direction().point3());
|
||||||
Matrix36 DE_;
|
Matrix36 DE_;
|
||||||
Point3 q = pose.transform_to(p, DE ? &DE_ : 0, Dpoint);
|
Point3 q = pose.transform_to(p, DE ? &DE_ : 0, Dpoint);
|
||||||
if (DE) {
|
if (DE) {
|
||||||
// DE returned by pose.transform_to is 3*6, but we need it to be 3*5
|
// DE returned by pose.transform_to is 3*6, but we need it to be 3*5
|
||||||
// The last 3 columns are derivative with respect to change in translation
|
// The last 3 columns are derivative with respect to change in translation
|
||||||
// The derivative of translation with respect to a 2D sphere delta is 3*2 aTb_.basis()
|
// The derivative of translation with respect to a 2D sphere delta is 3*2 direction().basis()
|
||||||
// Duy made an educated guess that this needs to be rotated to the local frame
|
// Duy made an educated guess that this needs to be rotated to the local frame
|
||||||
Matrix35 H;
|
Matrix35 H;
|
||||||
H << DE_.block < 3, 3 > (0, 0), -aRb_.transpose() * aTb_.basis();
|
H << DE_.block < 3, 3 > (0, 0), -rotation().transpose() * direction().basis();
|
||||||
*DE = H;
|
*DE = H;
|
||||||
}
|
}
|
||||||
return q;
|
return q;
|
||||||
|
|
@ -81,17 +63,17 @@ EssentialMatrix EssentialMatrix::rotate(const Rot3& cRb,
|
||||||
OptionalJacobian<5, 5> HE, OptionalJacobian<5, 3> HR) const {
|
OptionalJacobian<5, 5> HE, OptionalJacobian<5, 3> HR) const {
|
||||||
|
|
||||||
// The rotation must be conjugated to act in the camera frame
|
// The rotation must be conjugated to act in the camera frame
|
||||||
Rot3 c1Rc2 = aRb_.conjugate(cRb);
|
Rot3 c1Rc2 = rotation().conjugate(cRb);
|
||||||
|
|
||||||
if (!HE && !HR) {
|
if (!HE && !HR) {
|
||||||
// Rotate translation direction and return
|
// Rotate translation direction and return
|
||||||
Unit3 c1Tc2 = cRb * aTb_;
|
Unit3 c1Tc2 = cRb * direction();
|
||||||
return EssentialMatrix(c1Rc2, c1Tc2);
|
return EssentialMatrix(c1Rc2, c1Tc2);
|
||||||
} else {
|
} else {
|
||||||
// Calculate derivatives
|
// Calculate derivatives
|
||||||
Matrix23 D_c1Tc2_cRb; // 2*3
|
Matrix23 D_c1Tc2_cRb; // 2*3
|
||||||
Matrix2 D_c1Tc2_aTb; // 2*2
|
Matrix2 D_c1Tc2_aTb; // 2*2
|
||||||
Unit3 c1Tc2 = cRb.rotate(aTb_, D_c1Tc2_cRb, D_c1Tc2_aTb);
|
Unit3 c1Tc2 = cRb.rotate(direction(), D_c1Tc2_cRb, D_c1Tc2_aTb);
|
||||||
if (HE)
|
if (HE)
|
||||||
*HE << cRb.matrix(), Matrix32::Zero(), //
|
*HE << cRb.matrix(), Matrix32::Zero(), //
|
||||||
Matrix23::Zero(), D_c1Tc2_aTb;
|
Matrix23::Zero(), D_c1Tc2_aTb;
|
||||||
|
|
@ -113,8 +95,8 @@ double EssentialMatrix::error(const Vector3& vA, const Vector3& vB, //
|
||||||
if (H) {
|
if (H) {
|
||||||
// See math.lyx
|
// See math.lyx
|
||||||
Matrix13 HR = vA.transpose() * E_ * skewSymmetric(-vB);
|
Matrix13 HR = vA.transpose() * E_ * skewSymmetric(-vB);
|
||||||
Matrix12 HD = vA.transpose() * skewSymmetric(-aRb_.matrix() * vB)
|
Matrix12 HD = vA.transpose() * skewSymmetric(-rotation().matrix() * vB)
|
||||||
* aTb_.basis();
|
* direction().basis();
|
||||||
*H << HR, HD;
|
*H << HR, HD;
|
||||||
}
|
}
|
||||||
return dot(vA, E_ * vB);
|
return dot(vA, E_ * vB);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,55 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtsam/base/Manifold.h>
|
||||||
|
|
||||||
|
namespace gtsam {
|
||||||
|
|
||||||
|
/// CRTP to construct the product manifold of two other manifolds, M1 and M2
|
||||||
|
/// Assumes manifold structure from M1 and M2, and binary constructor
|
||||||
|
template<class Derived, typename M1, typename M2>
|
||||||
|
class ProductManifold: public std::pair<M1, M2> {
|
||||||
|
BOOST_CONCEPT_ASSERT((IsManifold<M1>));
|
||||||
|
BOOST_CONCEPT_ASSERT((IsManifold<M2>));
|
||||||
|
|
||||||
|
private:
|
||||||
|
const M1& g() const {return this->first;}
|
||||||
|
const M2& h() const {return this->second;}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Dimension of the manifold
|
||||||
|
enum { dimension = M1::dimension + M2::dimension };
|
||||||
|
|
||||||
|
typedef Eigen::Matrix<double, dimension, 1> TangentVector;
|
||||||
|
|
||||||
|
/// Default constructor yields identity
|
||||||
|
ProductManifold():std::pair<M1,M2>(traits<M1>::Identity(),traits<M2>::Identity()) {}
|
||||||
|
|
||||||
|
// Construct from two subgroup elements
|
||||||
|
ProductManifold(const M1& g, const M2& h):std::pair<M1,M2>(g,h) {}
|
||||||
|
|
||||||
|
/// Retract delta to manifold
|
||||||
|
Derived retract(const TangentVector& xi) const {
|
||||||
|
return Derived(traits<M1>::Retract(g(),xi.head(M1::dimension)),
|
||||||
|
traits<M2>::Retract(h(),xi.tail(M2::dimension)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the coordinates in the tangent space
|
||||||
|
TangentVector localCoordinates(const Derived& other) const {
|
||||||
|
TangentVector xi;
|
||||||
|
xi << traits<M1>::Local(g(),other.g()), traits<M2>::Local(h(),other.h());
|
||||||
|
return xi;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define any direct product group to be a model of the multiplicative Group concept
|
||||||
|
template<class Derived, typename M1, typename M2>
|
||||||
|
struct traits<ProductManifold<Derived, M1, M2> > : internal::Manifold<
|
||||||
|
ProductManifold<Derived, M1, M2> > {
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gtsam
|
||||||
|
|
||||||
#include <gtsam/geometry/Pose3.h>
|
#include <gtsam/geometry/Pose3.h>
|
||||||
#include <gtsam/geometry/Unit3.h>
|
#include <gtsam/geometry/Unit3.h>
|
||||||
#include <gtsam/geometry/Point2.h>
|
#include <gtsam/geometry/Point2.h>
|
||||||
|
|
@ -20,18 +69,15 @@ namespace gtsam {
|
||||||
* but here we choose instead to parameterize it as a (Rot3,Unit3) pair.
|
* but here we choose instead to parameterize it as a (Rot3,Unit3) pair.
|
||||||
* We can then non-linearly optimize immediately on this 5-dimensional manifold.
|
* We can then non-linearly optimize immediately on this 5-dimensional manifold.
|
||||||
*/
|
*/
|
||||||
class GTSAM_EXPORT EssentialMatrix {
|
class GTSAM_EXPORT EssentialMatrix : public ProductManifold<EssentialMatrix, Rot3, Unit3> {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Rot3 aRb_; ///< Rotation between a and b
|
typedef ProductManifold<EssentialMatrix, Rot3, Unit3> Base;
|
||||||
Unit3 aTb_; ///< translation direction from a to b
|
|
||||||
Matrix3 E_; ///< Essential matrix
|
Matrix3 E_; ///< Essential matrix
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum { dimension = 5 };
|
|
||||||
|
|
||||||
/// Static function to convert Point2 to homogeneous coordinates
|
/// Static function to convert Point2 to homogeneous coordinates
|
||||||
static Vector3 Homogeneous(const Point2& p) {
|
static Vector3 Homogeneous(const Point2& p) {
|
||||||
return Vector3(p.x(), p.y(), 1);
|
return Vector3(p.x(), p.y(), 1);
|
||||||
|
|
@ -42,12 +88,12 @@ public:
|
||||||
|
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
EssentialMatrix() :
|
EssentialMatrix() :
|
||||||
aTb_(1, 0, 0), E_(aTb_.skew()) {
|
Base(Rot3(), Unit3(1, 0, 0)), E_(direction().skew()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct from rotation and translation
|
/// Construct from rotation and translation
|
||||||
EssentialMatrix(const Rot3& aRb, const Unit3& aTb) :
|
EssentialMatrix(const Rot3& aRb, const Unit3& aTb) :
|
||||||
aRb_(aRb), aTb_(aTb), E_(aTb_.skew() * aRb_.matrix()) {
|
Base(aRb, aTb), E_(direction().skew() * rotation().matrix()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Named constructor converting a Pose3 with scale to EssentialMatrix (no scale)
|
/// Named constructor converting a Pose3 with scale to EssentialMatrix (no scale)
|
||||||
|
|
@ -72,43 +118,23 @@ public:
|
||||||
|
|
||||||
/// assert equality up to a tolerance
|
/// assert equality up to a tolerance
|
||||||
bool equals(const EssentialMatrix& other, double tol = 1e-8) const {
|
bool equals(const EssentialMatrix& other, double tol = 1e-8) const {
|
||||||
return aRb_.equals(other.aRb_, tol) && aTb_.equals(other.aTb_, tol);
|
return rotation().equals(other.rotation(), tol)
|
||||||
|
&& direction().equals(other.direction(), tol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @name Manifold
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Dimensionality of tangent space = 5 DOF
|
|
||||||
inline static size_t Dim() {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the dimensionality of the tangent space
|
|
||||||
size_t dim() const {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retract delta to manifold
|
|
||||||
EssentialMatrix retract(const Vector& xi) const;
|
|
||||||
|
|
||||||
/// Compute the coordinates in the tangent space
|
|
||||||
Vector5 localCoordinates(const EssentialMatrix& other) const;
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// @name Essential matrix methods
|
/// @name Essential matrix methods
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Rotation
|
/// Rotation
|
||||||
inline const Rot3& rotation() const {
|
inline const Rot3& rotation() const {
|
||||||
return aRb_;
|
return this->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Direction
|
/// Direction
|
||||||
inline const Unit3& direction() const {
|
inline const Unit3& direction() const {
|
||||||
return aTb_;
|
return this->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return 3*3 matrix representation
|
/// Return 3*3 matrix representation
|
||||||
|
|
@ -118,12 +144,12 @@ public:
|
||||||
|
|
||||||
/// Return epipole in image_a , as Unit3 to allow for infinity
|
/// Return epipole in image_a , as Unit3 to allow for infinity
|
||||||
inline const Unit3& epipole_a() const {
|
inline const Unit3& epipole_a() const {
|
||||||
return aTb_; // == direction()
|
return direction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return epipole in image_b, as Unit3 to allow for infinity
|
/// Return epipole in image_b, as Unit3 to allow for infinity
|
||||||
inline Unit3 epipole_b() const {
|
inline Unit3 epipole_b() const {
|
||||||
return aRb_.unrotate(aTb_); // == rotation.unrotate(direction())
|
return rotation().unrotate(direction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -180,8 +206,8 @@ private:
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
template<class ARCHIVE>
|
template<class ARCHIVE>
|
||||||
void serialize(ARCHIVE & ar, const unsigned int /*version*/) {
|
void serialize(ARCHIVE & ar, const unsigned int /*version*/) {
|
||||||
ar & BOOST_SERIALIZATION_NVP(aRb_);
|
ar & BOOST_SERIALIZATION_NVP(rotation());
|
||||||
ar & BOOST_SERIALIZATION_NVP(aTb_);
|
ar & BOOST_SERIALIZATION_NVP(direction());
|
||||||
|
|
||||||
ar & boost::serialization::make_nvp("E11", E_(0,0));
|
ar & boost::serialization::make_nvp("E11", E_(0,0));
|
||||||
ar & boost::serialization::make_nvp("E12", E_(0,1));
|
ar & boost::serialization::make_nvp("E12", E_(0,1));
|
||||||
|
|
@ -195,7 +221,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue