/* * @file EssentialMatrix.h * @brief EssentialMatrix class * @author Frank Dellaert * @date December 17, 2013 */ #pragma once #include #include #include #include #include #include namespace gtsam { /** * An essential matrix is like a Pose3, except with translation up to scale * It is named after the 3*3 matrix aEb = [aTb]x aRb from computer vision, * 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. */ class EssentialMatrix { private: Rot3 R_; ///< Rotation Unit3 t_; ///< Translation Matrix3 E_; ///< Essential matrix public: /// Static function to convert Point2 to homogeneous coordinates static Vector3 Homogeneous(const Point2& p) { return Vector3(p.x(), p.y(), 1); } /// @name Constructors and named constructors /// @{ /// Default constructor EssentialMatrix() :E_(t_.skew()) { } /// Construct from rotation and translation EssentialMatrix(const Rot3& aRb, const Unit3& aTb) : R_(aRb), t_(aTb), E_(t_.skew() * R_.matrix()) { } /// Named constructor with derivatives GTSAM_EXPORT static EssentialMatrix FromRotationAndDirection(const Rot3& aRb, const Unit3& aTb, OptionalJacobian<5, 3> H1 = {}, OptionalJacobian<5, 2> H2 = {}); /// Named constructor converting a Pose3 with scale to EssentialMatrix (no scale) GTSAM_EXPORT static EssentialMatrix FromPose3(const Pose3& _1P2_, OptionalJacobian<5, 6> H = {}); /// Random, using Rot3::Random and Unit3::Random template static EssentialMatrix Random(Engine & rng) { return EssentialMatrix(Rot3::Random(rng), Unit3::Random(rng)); } virtual ~EssentialMatrix() {} /// @} /// @name Testable /// @{ /// print with optional string GTSAM_EXPORT void print(const std::string& s = "") const; /// assert equality up to a tolerance bool equals(const EssentialMatrix& other, double tol = 1e-8) const { return R_.equals(other.R_, tol) && t_.equals(other.t_, tol); } /// @} /// @name Manifold /// @{ enum { dimension = 5 }; inline static size_t Dim() { return dimension;} inline size_t dim() const { return dimension;} typedef OptionalJacobian ChartJacobian; /// Retract delta to manifold EssentialMatrix retract(const Vector5& xi) const { return EssentialMatrix(R_.retract(xi.head<3>()), t_.retract(xi.tail<2>())); } /// Compute the coordinates in the tangent space Vector5 localCoordinates(const EssentialMatrix& other) const { auto v1 = R_.localCoordinates(other.R_); auto v2 = t_.localCoordinates(other.t_); Vector5 v; v << v1, v2; return v; } /// @} /// @name Essential matrix methods /// @{ /// Rotation inline const Rot3& rotation() const { return R_; } /// Direction inline const Unit3& direction() const { return t_; } /// Return 3*3 matrix representation inline const Matrix3& matrix() const { return E_; } /// Return epipole in image_a , as Unit3 to allow for infinity inline const Unit3& epipole_a() const { return t_; } /// Return epipole in image_b, as Unit3 to allow for infinity inline Unit3 epipole_b() const { return R_.unrotate(t_); } /** * @brief takes point in world coordinates and transforms it to pose with |t|==1 * @param p point in world coordinates * @param DE optional 3*5 Jacobian wrpt to E * @param Dpoint optional 3*3 Jacobian wrpt point * @return point in pose coordinates */ GTSAM_EXPORT Point3 transformTo(const Point3& p, OptionalJacobian<3, 5> DE = {}, OptionalJacobian<3, 3> Dpoint = {}) const; /** * Given essential matrix E in camera frame B, convert to body frame C * @param cRb rotation from body frame to camera frame * @param E essential matrix E in camera frame C */ GTSAM_EXPORT EssentialMatrix rotate(const Rot3& cRb, OptionalJacobian<5, 5> HE = {}, OptionalJacobian<5, 3> HR = {}) const; /** * Given essential matrix E in camera frame B, convert to body frame C * @param cRb rotation from body frame to camera frame * @param E essential matrix E in camera frame C */ friend EssentialMatrix operator*(const Rot3& cRb, const EssentialMatrix& E) { return E.rotate(cRb); } /// epipolar error, algebraic GTSAM_EXPORT double error(const Vector3& vA, const Vector3& vB, OptionalJacobian<1, 5> H = {}) const; /// @} /// @name Streaming operators /// @{ /// stream to stream GTSAM_EXPORT friend std::ostream& operator <<(std::ostream& os, const EssentialMatrix& E); /// stream from stream GTSAM_EXPORT friend std::istream& operator >>(std::istream& is, EssentialMatrix& E); /// @} private: /// @name Advanced Interface /// @{ #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION /** Serialization function */ friend class boost::serialization::access; template void serialize(ARCHIVE & ar, const unsigned int /*version*/) { ar & BOOST_SERIALIZATION_NVP(R_); ar & BOOST_SERIALIZATION_NVP(t_); ar & boost::serialization::make_nvp("E11", E_(0, 0)); ar & boost::serialization::make_nvp("E12", E_(0, 1)); ar & boost::serialization::make_nvp("E13", E_(0, 2)); ar & boost::serialization::make_nvp("E21", E_(1, 0)); ar & boost::serialization::make_nvp("E22", E_(1, 1)); ar & boost::serialization::make_nvp("E23", E_(1, 2)); ar & boost::serialization::make_nvp("E31", E_(2, 0)); ar & boost::serialization::make_nvp("E32", E_(2, 1)); ar & boost::serialization::make_nvp("E33", E_(2, 2)); } #endif /// @} public: GTSAM_MAKE_ALIGNED_OPERATOR_NEW }; template<> struct traits : public internal::Manifold {}; template<> struct traits : public internal::Manifold {}; } // namespace gtsam