diff --git a/.cproject b/.cproject
index 1dcc51dfe..d42d2b0e0 100644
--- a/.cproject
+++ b/.cproject
@@ -2777,6 +2777,14 @@
true
true
+
+ make
+ -j4
+ testCustomChartExpression.run
+ true
+ true
+ true
+
make
-j2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6e59cc57..0888a394e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,8 +101,6 @@ if(MSVC)
add_definitions(-DBOOST_ALL_NO_LIB)
add_definitions(-DBOOST_ALL_DYN_LINK)
endif()
- # Also disable certain warnings
- add_definitions(/wd4503)
endif()
find_package(Boost 1.43 COMPONENTS serialization system filesystem thread program_options date_time regex timer chrono)
@@ -281,7 +279,7 @@ include_directories(BEFORE
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
- add_definitions(/wd4251 /wd4275 /wd4251 /wd4661 /wd4344) # Disable non-DLL-exported base class and other warnings
+ add_definitions(/wd4251 /wd4275 /wd4251 /wd4661 /wd4344 /wd4503) # Disable non-DLL-exported base class and other warnings
endif()
# GCC 4.8+ complains about local typedefs which we use for shared_ptr etc.
@@ -330,7 +328,6 @@ endif(GTSAM_BUILD_UNSTABLE)
# Install config and export files
GtsamMakeConfigFile(GTSAM "${CMAKE_CURRENT_SOURCE_DIR}/gtsam_extra.cmake.in")
-message("GTSAM export: ${GTSAM_EXPORTED_TARGETS}")
export(TARGETS ${GTSAM_EXPORTED_TARGETS} FILE GTSAM-exports.cmake)
diff --git a/examples/SFMExample_SmartFactor.cpp b/examples/SFMExample_SmartFactor.cpp
index 9e9c74edc..b999e6600 100644
--- a/examples/SFMExample_SmartFactor.cpp
+++ b/examples/SFMExample_SmartFactor.cpp
@@ -61,8 +61,7 @@ using namespace std;
using namespace gtsam;
// Make the typename short so it looks much cleaner
-typedef gtsam::SmartProjectionPoseFactor SmartFactor;
+typedef gtsam::SmartProjectionPoseFactor SmartFactor;
/* ************************************************************************* */
int main(int argc, char* argv[]) {
diff --git a/gtsam.h b/gtsam.h
index 0ceda6db5..d63563028 100644
--- a/gtsam.h
+++ b/gtsam.h
@@ -2272,7 +2272,7 @@ virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor {
};
#include
-template
+template
virtual class SmartProjectionPoseFactor : gtsam::NonlinearFactor {
SmartProjectionPoseFactor(double rankTol, double linThreshold,
@@ -2288,7 +2288,7 @@ virtual class SmartProjectionPoseFactor : gtsam::NonlinearFactor {
//void serialize() const;
};
-typedef gtsam::SmartProjectionPoseFactor SmartProjectionPose3Factor;
+typedef gtsam::SmartProjectionPoseFactor SmartProjectionPose3Factor;
#include
diff --git a/gtsam/CMakeLists.txt b/gtsam/CMakeLists.txt
index b58a5b4b8..0ebd6c07d 100644
--- a/gtsam/CMakeLists.txt
+++ b/gtsam/CMakeLists.txt
@@ -10,7 +10,7 @@ set (gtsam_subdirs
linear
nonlinear
slam
- navigation
+ navigation
)
set(gtsam_srcs)
@@ -74,8 +74,8 @@ set(gtsam_srcs
${linear_srcs}
${nonlinear_srcs}
${slam_srcs}
- ${navigation_srcs}
- ${gtsam_core_headers}
+ ${navigation_srcs}
+ ${gtsam_core_headers}
)
# Generate and install config and dllexport files
@@ -92,8 +92,6 @@ set(gtsam_version ${GTSAM_VERSION_MAJOR}.${GTSAM_VERSION_MINOR}.${GTSAM_VERSIO
set(gtsam_soversion ${GTSAM_VERSION_MAJOR})
message(STATUS "GTSAM Version: ${gtsam_version}")
message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
-message("GTSAM Additional: ${GTSAM_ADDITIONAL_LIBRARIES}")
-message("GTSAM Exports: ${GTSAM_EXPORTED_TARGETS}")
# build shared and static versions of the library
if (GTSAM_BUILD_STATIC_LIBRARY)
diff --git a/gtsam/base/numericalDerivative.h b/gtsam/base/numericalDerivative.h
index 30136d9f2..f2c4566bb 100644
--- a/gtsam/base/numericalDerivative.h
+++ b/gtsam/base/numericalDerivative.h
@@ -524,71 +524,5 @@ inline Matrix numericalHessian323(double (*f)(const X1&, const X2&, const X3&),
delta);
}
-// The benefit of this method is that it does not need to know what types are involved
-// to evaluate the factor. If all the machinery of gtsam is working correctly, we should
-// get the correct numerical derivatives out the other side.
-template
-JacobianFactor computeNumericalDerivativeJacobianFactor(const FactorType& factor,
- const Values& values,
- double fd_step) {
- Eigen::VectorXd e = factor.unwhitenedError(values);
- const size_t rows = e.size();
-
- std::map jacobians;
- typename FactorType::const_iterator key_it = factor.begin();
- VectorValues dX = values.zeroVectors();
- for(; key_it != factor.end(); ++key_it) {
- size_t key = *key_it;
- // Compute central differences using the values struct.
- const size_t cols = dX.dim(key);
- Matrix J = Matrix::Zero(rows, cols);
- for(size_t col = 0; col < cols; ++col) {
- Eigen::VectorXd dx = Eigen::VectorXd::Zero(cols);
- dx[col] = fd_step;
- dX[key] = dx;
- Values eval_values = values.retract(dX);
- Eigen::VectorXd left = factor.unwhitenedError(eval_values);
- dx[col] = -fd_step;
- dX[key] = dx;
- eval_values = values.retract(dX);
- Eigen::VectorXd right = factor.unwhitenedError(eval_values);
- J.col(col) = (left - right) * (1.0/(2.0 * fd_step));
- }
- jacobians[key] = J;
- }
-
- // Next step...return JacobianFactor
- return JacobianFactor(jacobians, -e);
-}
-
-template
-void testFactorJacobians(TestResult& result_,
- const std::string& name_,
- const FactorType& f,
- const gtsam::Values& values,
- double fd_step,
- double tolerance) {
- // Check linearization
- JacobianFactor expected = computeNumericalDerivativeJacobianFactor(f, values, fd_step);
- boost::shared_ptr gf = f.linearize(values);
- boost::shared_ptr jf = //
- boost::dynamic_pointer_cast(gf);
-
- typedef std::pair Jacobian;
- Jacobian evalJ = jf->jacobianUnweighted();
- Jacobian estJ = expected.jacobianUnweighted();
- EXPECT(assert_equal(evalJ.first, estJ.first, tolerance));
- EXPECT(assert_equal(evalJ.second, Eigen::VectorXd::Zero(evalJ.second.size()), tolerance));
- EXPECT(assert_equal(estJ.second, Eigen::VectorXd::Zero(evalJ.second.size()), tolerance));
-}
-
} // namespace gtsam
-/// \brief Check the Jacobians produced by a factor against finite differences.
-/// \param factor The factor to test.
-/// \param values Values filled in for testing the Jacobians.
-/// \param numerical_derivative_step The step to use when computing the numerical derivative Jacobians
-/// \param tolerance The numerical tolerance to use when comparing Jacobians.
-#define EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, numerical_derivative_step, tolerance) \
- { gtsam::testFactorJacobians(result_, name_, factor, values, numerical_derivative_step, tolerance); }
-
diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h
index 811264967..b47153547 100644
--- a/gtsam/geometry/Cal3_S2Stereo.h
+++ b/gtsam/geometry/Cal3_S2Stereo.h
@@ -52,6 +52,11 @@ namespace gtsam {
/// constructor from vector
Cal3_S2Stereo(const Vector &d): K_(d(0), d(1), d(2), d(3), d(4)), b_(d(5)){}
+ /// easy constructor; field-of-view in degrees, assumes zero skew
+ Cal3_S2Stereo(double fov, int w, int h, double b) :
+ K_(fov, w, h), b_(b) {
+ }
+
/// @}
/// @name Testable
/// @{
diff --git a/gtsam/geometry/StereoCamera.cpp b/gtsam/geometry/StereoCamera.cpp
index f48c188aa..b9e03c01d 100644
--- a/gtsam/geometry/StereoCamera.cpp
+++ b/gtsam/geometry/StereoCamera.cpp
@@ -30,7 +30,8 @@ namespace gtsam {
/* ************************************************************************* */
StereoPoint2 StereoCamera::project(const Point3& point,
- boost::optional H1, boost::optional H2) const {
+ boost::optional H1, boost::optional H2,
+ boost::optional H3) const {
#ifdef STEREOCAMERA_CHAIN_RULE
const Point3 q = leftCamPose_.transform_to(point, H1, H2);
diff --git a/gtsam/geometry/StereoCamera.h b/gtsam/geometry/StereoCamera.h
index 9c326a8d2..60ea7693d 100644
--- a/gtsam/geometry/StereoCamera.h
+++ b/gtsam/geometry/StereoCamera.h
@@ -114,21 +114,18 @@ public:
/*
* project 3D point and compute optional derivatives
+ * @param H1 derivative with respect to pose
+ * @param H2 derivative with respect to point
+ * @param H3 IGNORED (for calibration)
*/
StereoPoint2 project(const Point3& point,
boost::optional H1 = boost::none,
- boost::optional H2 = boost::none) const;
+ boost::optional H2 = boost::none,
+ boost::optional H3 = boost::none) const;
- /*
- * to accomodate tsam's assumption that K is estimated, too
+ /**
+ *
*/
- StereoPoint2 project(const Point3& point,
- boost::optional H1,
- boost::optional H1_k,
- boost::optional H2) const {
- return project(point, H1, H2);
- }
-
Point3 backproject(const StereoPoint2& z) const {
Vector measured = z.vector();
double Z = K_->baseline()*K_->fx()/(measured[0]-measured[1]);
diff --git a/gtsam/geometry/StereoPoint2.cpp b/gtsam/geometry/StereoPoint2.cpp
index f599a2dea..cd6f09507 100644
--- a/gtsam/geometry/StereoPoint2.cpp
+++ b/gtsam/geometry/StereoPoint2.cpp
@@ -19,10 +19,18 @@
#include
using namespace std;
-using namespace gtsam;
+
+namespace gtsam {
/* ************************************************************************* */
void StereoPoint2::print(const string& s) const {
cout << s << "(" << uL_ << ", " << uR_ << ", " << v_ << ")" << endl;
}
+
/* ************************************************************************* */
+ostream &operator<<(ostream &os, const StereoPoint2& p) {
+ os << '(' << p.uL() << ", " << p.uR() << ", " << p.v() << ')';
+ return os;
+}
+
+} // namespace gtsam
diff --git a/gtsam/geometry/StereoPoint2.h b/gtsam/geometry/StereoPoint2.h
index d62a3f067..694bf525b 100644
--- a/gtsam/geometry/StereoPoint2.h
+++ b/gtsam/geometry/StereoPoint2.h
@@ -88,7 +88,7 @@ namespace gtsam {
StereoPoint2 operator-(const StereoPoint2& b) const {
return StereoPoint2(uL_ - b.uL_, uR_ - b.uR_, v_ - b.v_);
}
-
+
/// @}
/// @name Manifold
/// @{
@@ -143,15 +143,18 @@ namespace gtsam {
}
/** convenient function to get a Point2 from the left image */
- inline Point2 point2(){
+ Point2 point2() const {
return Point2(uL_, v_);
}
/** convenient function to get a Point2 from the right image */
- inline Point2 right(){
+ Point2 right() const {
return Point2(uR_, v_);
}
+ /// Streaming
+ GTSAM_EXPORT friend std::ostream &operator<<(std::ostream &os, const StereoPoint2& p);
+
private:
/// @}
diff --git a/gtsam/nonlinear/Values-inl.h b/gtsam/nonlinear/Values-inl.h
index 4595a70ed..e983ccb17 100644
--- a/gtsam/nonlinear/Values-inl.h
+++ b/gtsam/nonlinear/Values-inl.h
@@ -302,8 +302,8 @@ namespace gtsam {
}
// overloaded insert with chart initializer
- template
- void Values::insert(Key j, const ValueType& val, ChartInit chart) {
+ template
+ void Values::insert(Key j, const ValueType& val, Chart chart) {
insert(j, static_cast(ChartValue(val, chart)));
}
@@ -320,8 +320,8 @@ namespace gtsam {
}
// update with chart initializer, /todo: perhaps there is a way to init chart from old value...
- template
- void Values::update(Key j, const ValueType& val, ChartInit chart) {
+ template
+ void Values::update(Key j, const ValueType& val, Chart chart) {
update(j, static_cast(ChartValue(val, chart)));
}
diff --git a/gtsam/nonlinear/Values.h b/gtsam/nonlinear/Values.h
index e4a27849d..d00baa0d9 100644
--- a/gtsam/nonlinear/Values.h
+++ b/gtsam/nonlinear/Values.h
@@ -263,8 +263,8 @@ namespace gtsam {
void insert(Key j, const ValueType& val);
/// overloaded insert version that also specifies a chart initializer
- template
- void insert(Key j, const ValueType& val, ChartInit chart);
+ template
+ void insert(Key j, const ValueType& val, Chart chart);
/** insert that mimics the STL map insert - if the value already exists, the map is not modified
@@ -288,8 +288,8 @@ namespace gtsam {
void update(Key j, const T& val);
/// overloaded insert version that also specifies a chart initializer
- template
- void update(Key j, const T& val, ChartInit chart);
+ template
+ void update(Key j, const T& val, Chart chart);
/** update the current available values without adding new ones */
void update(const Values& values);
diff --git a/gtsam/slam/JacobianFactorQ.h b/gtsam/slam/JacobianFactorQ.h
index f4dfb9422..923edddb7 100644
--- a/gtsam/slam/JacobianFactorQ.h
+++ b/gtsam/slam/JacobianFactorQ.h
@@ -12,10 +12,10 @@ namespace gtsam {
/**
* JacobianFactor for Schur complement that uses Q noise model
*/
-template
-class JacobianFactorQ: public JacobianSchurFactor {
+template
+class JacobianFactorQ: public JacobianSchurFactor {
- typedef JacobianSchurFactor Base;
+ typedef JacobianSchurFactor Base;
public:
@@ -25,7 +25,7 @@ public:
/// Empty constructor with keys
JacobianFactorQ(const FastVector& keys,
- const SharedDiagonal& model = SharedDiagonal()) : JacobianSchurFactor() {
+ const SharedDiagonal& model = SharedDiagonal()) : JacobianSchurFactor() {
Matrix zeroMatrix = Matrix::Zero(0,D);
Vector zeroVector = Vector::Zero(0);
typedef std::pair KeyMatrix;
@@ -40,8 +40,8 @@ public:
JacobianFactorQ(const std::vector& Fblocks,
const Matrix& E, const Matrix3& P, const Vector& b,
const SharedDiagonal& model = SharedDiagonal()) :
- JacobianSchurFactor() {
- size_t j = 0, m2 = E.rows(), m = m2 / 2;
+ JacobianSchurFactor() {
+ size_t j = 0, m2 = E.rows(), m = m2 / ZDim;
// Calculate projector Q
Matrix Q = eye(m2) - E * P * E.transpose();
// Calculate pre-computed Jacobian matrices
@@ -49,9 +49,9 @@ public:
typedef std::pair KeyMatrix;
std::vector < KeyMatrix > QF;
QF.reserve(m);
- // Below, we compute each 2m*D block A_j = Q_j * F_j = (2m*2) * (2*D)
+ // Below, we compute each mZDim*D block A_j = Q_j * F_j = (mZDim*ZDim) * (Zdim*D)
BOOST_FOREACH(const typename Base::KeyMatrix2D& it, Fblocks)
- QF.push_back(KeyMatrix(it.first, Q.block(0, 2 * j++, m2, 2) * it.second));
+ QF.push_back(KeyMatrix(it.first, Q.block(0, ZDim * j++, m2, ZDim) * it.second));
// Which is then passed to the normal JacobianFactor constructor
JacobianFactor::fillTerms(QF, Q * b, model);
}
diff --git a/gtsam/slam/JacobianFactorQR.h b/gtsam/slam/JacobianFactorQR.h
index a928106a8..ccd6e8756 100644
--- a/gtsam/slam/JacobianFactorQR.h
+++ b/gtsam/slam/JacobianFactorQR.h
@@ -12,10 +12,10 @@ namespace gtsam {
/**
* JacobianFactor for Schur complement that uses Q noise model
*/
-template
-class JacobianFactorQR: public JacobianSchurFactor {
+template
+class JacobianFactorQR: public JacobianSchurFactor {
- typedef JacobianSchurFactor Base;
+ typedef JacobianSchurFactor Base;
public:
@@ -25,14 +25,14 @@ public:
JacobianFactorQR(const std::vector& Fblocks,
const Matrix& E, const Matrix3& P, const Vector& b,
const SharedDiagonal& model = SharedDiagonal()) :
- JacobianSchurFactor() {
+ JacobianSchurFactor() {
// Create a number of Jacobian factors in a factor graph
GaussianFactorGraph gfg;
Symbol pointKey('p', 0);
size_t i = 0;
BOOST_FOREACH(const typename Base::KeyMatrix2D& it, Fblocks) {
- gfg.add(pointKey, E.block<2, 3>(2 * i, 0), it.first, it.second,
- b.segment<2>(2 * i), model);
+ gfg.add(pointKey, E.block(ZDim * i, 0), it.first, it.second,
+ b.segment(ZDim * i), model);
i += 1;
}
//gfg.print("gfg");
diff --git a/gtsam/slam/JacobianFactorSVD.h b/gtsam/slam/JacobianFactorSVD.h
index e28185038..e0a5f4566 100644
--- a/gtsam/slam/JacobianFactorSVD.h
+++ b/gtsam/slam/JacobianFactorSVD.h
@@ -11,12 +11,12 @@ namespace gtsam {
/**
* JacobianFactor for Schur complement that uses Q noise model
*/
-template
-class JacobianFactorSVD: public JacobianSchurFactor {
+template
+class JacobianFactorSVD: public JacobianSchurFactor {
public:
- typedef Eigen::Matrix Matrix2D;
+ typedef Eigen::Matrix Matrix2D; // e.g 2 x 6 with Z=Point2
typedef std::pair KeyMatrix2D;
typedef std::pair KeyMatrix;
@@ -25,7 +25,7 @@ public:
/// Empty constructor with keys
JacobianFactorSVD(const FastVector& keys,
- const SharedDiagonal& model = SharedDiagonal()) : JacobianSchurFactor() {
+ const SharedDiagonal& model = SharedDiagonal()) : JacobianSchurFactor() {
Matrix zeroMatrix = Matrix::Zero(0,D);
Vector zeroVector = Vector::Zero(0);
std::vector QF;
@@ -37,9 +37,9 @@ public:
/// Constructor
JacobianFactorSVD(const std::vector& Fblocks, const Matrix& Enull, const Vector& b,
- const SharedDiagonal& model = SharedDiagonal()) : JacobianSchurFactor() {
- size_t numKeys = Enull.rows() / 2;
- size_t j = 0, m2 = 2*numKeys-3;
+ const SharedDiagonal& model = SharedDiagonal()) : JacobianSchurFactor() {
+ size_t numKeys = Enull.rows() / ZDim;
+ size_t j = 0, m2 = ZDim*numKeys-3;
// PLAIN NULL SPACE TRICK
// Matrix Q = Enull * Enull.transpose();
// BOOST_FOREACH(const KeyMatrix2D& it, Fblocks)
@@ -48,7 +48,7 @@ public:
std::vector QF;
QF.reserve(numKeys);
BOOST_FOREACH(const KeyMatrix2D& it, Fblocks)
- QF.push_back(KeyMatrix(it.first, (Enull.transpose()).block(0, 2 * j++, m2, 2) * it.second));
+ QF.push_back(KeyMatrix(it.first, (Enull.transpose()).block(0, ZDim * j++, m2, ZDim) * it.second));
JacobianFactor::fillTerms(QF, Enull.transpose() * b, model);
}
};
diff --git a/gtsam/slam/JacobianSchurFactor.h b/gtsam/slam/JacobianSchurFactor.h
index 2beecc264..5d28bbada 100644
--- a/gtsam/slam/JacobianSchurFactor.h
+++ b/gtsam/slam/JacobianSchurFactor.h
@@ -18,12 +18,12 @@ namespace gtsam {
/**
* JacobianFactor for Schur complement that uses Q noise model
*/
-template
+template
class JacobianSchurFactor: public JacobianFactor {
public:
- typedef Eigen::Matrix Matrix2D;
+ typedef Eigen::Matrix Matrix2D;
typedef std::pair KeyMatrix2D;
// Use eigen magic to access raw memory
diff --git a/gtsam/slam/SmartFactorBase.h b/gtsam/slam/SmartFactorBase.h
index 8ae26e7cd..d9e7b9819 100644
--- a/gtsam/slam/SmartFactorBase.h
+++ b/gtsam/slam/SmartFactorBase.h
@@ -19,16 +19,16 @@
#pragma once
-#include "JacobianFactorQ.h"
-#include "JacobianFactorSVD.h"
-#include "RegularImplicitSchurFactor.h"
-#include "RegularHessianFactor.h"
+#include
+#include
+#include
+#include
#include
-#include
+#include // for Cheirality exception
+#include
#include
#include
-#include
#include
#include
@@ -36,40 +36,48 @@
namespace gtsam {
/// Base class with no internal point, completely functional
-template
+template
class SmartFactorBase: public NonlinearFactor {
+
protected:
// Keep a copy of measurement and calibration for I/O
- std::vector measured_; ///< 2D measurement for each of the m views
+ std::vector measured_; ///< 2D measurement for each of the m views
std::vector noise_; ///< noise model used
///< (important that the order is the same as the keys that we use to create the factor)
boost::optional body_P_sensor_; ///< The pose of the sensor in the body frame (one for all cameras)
+ static const int ZDim = traits::dimension::value; ///< Measurement dimension
+
/// Definitions for blocks of F
- typedef Eigen::Matrix Matrix2D; // F
- typedef Eigen::Matrix MatrixD2; // F'
+ typedef Eigen::Matrix Matrix2D; // F
+ typedef Eigen::Matrix MatrixD2; // F'
typedef std::pair KeyMatrix2D; // Fblocks
typedef Eigen::Matrix MatrixDD; // camera hessian block
- typedef Eigen::Matrix Matrix23;
+ typedef Eigen::Matrix Matrix23;
typedef Eigen::Matrix VectorD;
- typedef Eigen::Matrix Matrix2;
+ typedef Eigen::Matrix Matrix2;
/// shorthand for base class type
typedef NonlinearFactor Base;
/// shorthand for this class
- typedef SmartFactorBase This;
+ typedef SmartFactorBase This;
+
public:
+
+
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
/// shorthand for a smart pointer to a factor
typedef boost::shared_ptr shared_ptr;
/// shorthand for a pinhole camera
- typedef PinholeCamera Camera;
- typedef std::vector Cameras;
+ typedef CAMERA Camera;
+ typedef std::vector Cameras;
/**
* Constructor
@@ -89,7 +97,7 @@ public:
* @param poseKey is the index corresponding to the camera observing the landmark
* @param noise_i is the measurement noise
*/
- void add(const Point2& measured_i, const Key& poseKey_i,
+ void add(const Z& measured_i, const Key& poseKey_i,
const SharedNoiseModel& noise_i) {
this->measured_.push_back(measured_i);
this->keys_.push_back(poseKey_i);
@@ -100,7 +108,7 @@ public:
* variant of the previous add: adds a bunch of measurements, together with the camera keys and noises
*/
// ****************************************************************************************************
- void add(std::vector& measurements, std::vector& poseKeys,
+ void add(std::vector& measurements, std::vector& poseKeys,
std::vector& noises) {
for (size_t i = 0; i < measurements.size(); i++) {
this->measured_.push_back(measurements.at(i));
@@ -113,7 +121,7 @@ public:
* variant of the previous add: adds a bunch of measurements and uses the same noise model for all of them
*/
// ****************************************************************************************************
- void add(std::vector& measurements, std::vector& poseKeys,
+ void add(std::vector& measurements, std::vector& poseKeys,
const SharedNoiseModel& noise) {
for (size_t i = 0; i < measurements.size(); i++) {
this->measured_.push_back(measurements.at(i));
@@ -127,7 +135,8 @@ public:
* The noise is assumed to be the same for all measurements
*/
// ****************************************************************************************************
- void add(const SfM_Track& trackToAdd, const SharedNoiseModel& noise) {
+ template
+ void add(const SFM_TRACK& trackToAdd, const SharedNoiseModel& noise) {
for (size_t k = 0; k < trackToAdd.number_measurements(); k++) {
this->measured_.push_back(trackToAdd.measurements[k].second);
this->keys_.push_back(trackToAdd.measurements[k].first);
@@ -136,7 +145,7 @@ public:
}
/** return the measurements */
- const std::vector& measured() const {
+ const std::vector& measured() const {
return measured_;
}
@@ -179,18 +188,18 @@ public:
}
// ****************************************************************************************************
- /// Calculate vector of re-projection errors, before applying noise model
+// /// Calculate vector of re-projection errors, before applying noise model
Vector reprojectionError(const Cameras& cameras, const Point3& point) const {
- Vector b = zero(2 * cameras.size());
+ Vector b = zero(ZDim * cameras.size());
size_t i = 0;
- BOOST_FOREACH(const Camera& camera, cameras) {
- const Point2& zi = this->measured_.at(i);
+ BOOST_FOREACH(const CAMERA& camera, cameras) {
+ const Z& zi = this->measured_.at(i);
try {
- Point2 e(camera.project(point) - zi);
- b[2 * i] = e.x();
- b[2 * i + 1] = e.y();
+ Z e(camera.project(point) - zi);
+ b[ZDim * i] = e.x();
+ b[ZDim * i + 1] = e.y();
} catch (CheiralityException& e) {
std::cout << "Cheirality exception " << std::endl;
exit(EXIT_FAILURE);
@@ -215,10 +224,10 @@ public:
double overallError = 0;
size_t i = 0;
- BOOST_FOREACH(const Camera& camera, cameras) {
- const Point2& zi = this->measured_.at(i);
+ BOOST_FOREACH(const CAMERA& camera, cameras) {
+ const Z& zi = this->measured_.at(i);
try {
- Point2 reprojectionError(camera.project(point) - zi);
+ Z reprojectionError(camera.project(point) - zi);
overallError += 0.5
* this->noise_.at(i)->distance(reprojectionError.vector());
} catch (CheiralityException&) {
@@ -236,19 +245,19 @@ public:
const Point3& point) const {
int numKeys = this->keys_.size();
- E = zeros(2 * numKeys, 3);
+ E = zeros(ZDim * numKeys, 3);
Vector b = zero(2 * numKeys);
- Matrix Ei(2, 3);
+ Matrix Ei(ZDim, 3);
for (size_t i = 0; i < this->measured_.size(); i++) {
try {
- cameras[i].project(point, boost::none, Ei);
+ cameras[i].project(point, boost::none, Ei, boost::none);
} catch (CheiralityException& e) {
std::cout << "Cheirality exception " << std::endl;
exit(EXIT_FAILURE);
}
this->noise_.at(i)->WhitenSystem(Ei, b);
- E.block<2, 3>(2 * i, 0) = Ei;
+ E.block(ZDim * i, 0) = Ei;
}
// Matrix PointCov;
@@ -262,11 +271,11 @@ public:
Vector& b, const Cameras& cameras, const Point3& point) const {
size_t numKeys = this->keys_.size();
- E = zeros(2 * numKeys, 3);
- b = zero(2 * numKeys);
+ E = zeros(ZDim * numKeys, 3);
+ b = zero(ZDim * numKeys);
double f = 0;
- Matrix Fi(2, 6), Ei(2, 3), Hcali(2, D - 6), Hcam(2, D);
+ Matrix Fi(ZDim, 6), Ei(ZDim, 3), Hcali(ZDim, D - 6), Hcam(ZDim, D);
for (size_t i = 0; i < this->measured_.size(); i++) {
Vector bi;
@@ -288,12 +297,12 @@ public:
if (D == 6) { // optimize only camera pose
Fblocks.push_back(KeyMatrix2D(this->keys_[i], Fi));
} else {
- Hcam.block<2, 6>(0, 0) = Fi; // 2 x 6 block for the cameras
- Hcam.block<2, D - 6>(0, 6) = Hcali; // 2 x nrCal block for the cameras
+ Hcam.block(0, 0) = Fi; // ZDim x 6 block for the cameras
+ Hcam.block(0, 6) = Hcali; // ZDim x nrCal block for the cameras
Fblocks.push_back(KeyMatrix2D(this->keys_[i], Hcam));
}
- E.block<2, 3>(2 * i, 0) = Ei;
- subInsert(b, bi, 2 * i);
+ E.block(ZDim * i, 0) = Ei;
+ subInsert(b, bi, ZDim * i);
}
return f;
}
@@ -334,10 +343,10 @@ public:
std::vector Fblocks;
double f = computeJacobians(Fblocks, E, PointCov, b, cameras, point,
lambda);
- F = zeros(2 * numKeys, D * numKeys);
+ F = zeros(This::ZDim * numKeys, D * numKeys);
for (size_t i = 0; i < this->keys_.size(); ++i) {
- F.block<2, D>(2 * i, D * i) = Fblocks.at(i).second; // 2 x 6 block for the cameras
+ F.block(This::ZDim * i, D * i) = Fblocks.at(i).second; // ZDim x 6 block for the cameras
}
return f;
}
@@ -356,9 +365,9 @@ public:
// Do SVD on A
Eigen::JacobiSVD svd(E, Eigen::ComputeFullU);
Vector s = svd.singularValues();
- // Enull = zeros(2 * numKeys, 2 * numKeys - 3);
+ // Enull = zeros(ZDim * numKeys, ZDim * numKeys - 3);
size_t numKeys = this->keys_.size();
- Enull = svd.matrixU().block(0, 3, 2 * numKeys, 2 * numKeys - 3); // last 2m-3 columns
+ Enull = svd.matrixU().block(0, 3, ZDim * numKeys, ZDim * numKeys - 3); // last ZDimm-3 columns
return f;
}
@@ -372,11 +381,11 @@ public:
int numKeys = this->keys_.size();
std::vector Fblocks;
double f = computeJacobiansSVD(Fblocks, Enull, b, cameras, point);
- F.resize(2 * numKeys, D * numKeys);
+ F.resize(ZDim * numKeys, D * numKeys);
F.setZero();
for (size_t i = 0; i < this->keys_.size(); ++i)
- F.block<2, D>(2 * i, D * i) = Fblocks.at(i).second; // 2 x 6 block for the cameras
+ F.block(ZDim * i, D * i) = Fblocks.at(i).second; // ZDim x 6 block for the cameras
return f;
}
@@ -437,9 +446,9 @@ public:
int numKeys = this->keys_.size();
/// Compute Full F ????
- Matrix F = zeros(2 * numKeys, D * numKeys);
+ Matrix F = zeros(ZDim * numKeys, D * numKeys);
for (size_t i = 0; i < this->keys_.size(); ++i)
- F.block<2, D>(2 * i, D * i) = Fblocks.at(i).second; // 2 x 6 block for the cameras
+ F.block(ZDim * i, D * i) = Fblocks.at(i).second; // ZDim x 6 block for the cameras
Matrix H(D * numKeys, D * numKeys);
Vector gs_vector;
@@ -477,16 +486,16 @@ public:
for (size_t i1 = 0; i1 < numKeys; i1++) { // for each camera
const Matrix2D& Fi1 = Fblocks.at(i1).second;
- const Matrix23 Ei1_P = E.block<2, 3>(2 * i1, 0) * P;
+ const Matrix23 Ei1_P = E.block(ZDim * i1, 0) * P;
// D = (Dx2) * (2)
// (augmentedHessian.matrix()).block (i1,numKeys+1) = Fi1.transpose() * b.segment < 2 > (2 * i1); // F' * b
- augmentedHessian(i1, numKeys) = Fi1.transpose() * b.segment<2>(2 * i1) // F' * b
- - Fi1.transpose() * (Ei1_P * (E.transpose() * b)); // D = (Dx2) * (2x3) * (3*2m) * (2m x 1)
+ augmentedHessian(i1, numKeys) = Fi1.transpose() * b.segment(ZDim * i1) // F' * b
+ - Fi1.transpose() * (Ei1_P * (E.transpose() * b)); // D = (DxZDim) * (ZDimx3) * (3*ZDimm) * (ZDimm x 1)
- // (DxD) = (Dx2) * ( (2xD) - (2x3) * (3x2) * (2xD) )
+ // (DxD) = (DxZDim) * ( (ZDimxD) - (ZDimx3) * (3xZDim) * (ZDimxD) )
augmentedHessian(i1, i1) = Fi1.transpose()
- * (Fi1 - Ei1_P * E.block<2, 3>(2 * i1, 0).transpose() * Fi1);
+ * (Fi1 - Ei1_P * E.block(ZDim * i1, 0).transpose() * Fi1);
// upper triangular part of the hessian
for (size_t i2 = i1 + 1; i2 < numKeys; i2++) { // for each camera
@@ -494,7 +503,7 @@ public:
// (DxD) = (Dx2) * ( (2x2) * (2xD) )
augmentedHessian(i1, i2) = -Fi1.transpose()
- * (Ei1_P * E.block<2, 3>(2 * i2, 0).transpose() * Fi2);
+ * (Ei1_P * E.block(ZDim * i2, 0).transpose() * Fi2);
}
} // end of for over cameras
}
@@ -521,16 +530,16 @@ public:
// X X X X 14
const Matrix2D& Fi1 = Fblocks.at(i1).second;
- const Matrix23 Ei1_P = E.block<2, 3>(2 * i1, 0) * P;
+ const Matrix23 Ei1_P = E.block(ZDim * i1, 0) * P;
{ // for i1 = i2
// D = (Dx2) * (2)
- gs.at(i1) = Fi1.transpose() * b.segment<2>(2 * i1) // F' * b
- -Fi1.transpose() * (Ei1_P * (E.transpose() * b)); // D = (Dx2) * (2x3) * (3*2m) * (2m x 1)
+ gs.at(i1) = Fi1.transpose() * b.segment(ZDim * i1) // F' * b
+ -Fi1.transpose() * (Ei1_P * (E.transpose() * b)); // D = (DxZDim) * (ZDimx3) * (3*ZDimm) * (ZDimm x 1)
- // (DxD) = (Dx2) * ( (2xD) - (2x3) * (3x2) * (2xD) )
+ // (DxD) = (DxZDim) * ( (ZDimxD) - (ZDimx3) * (3xZDim) * (ZDimxD) )
Gs.at(GsIndex) = Fi1.transpose()
- * (Fi1 - Ei1_P * E.block<2, 3>(2 * i1, 0).transpose() * Fi1);
+ * (Fi1 - Ei1_P * E.block(ZDim * i1, 0).transpose() * Fi1);
GsIndex++;
}
// upper triangular part of the hessian
@@ -539,7 +548,7 @@ public:
// (DxD) = (Dx2) * ( (2x2) * (2xD) )
Gs.at(GsIndex) = -Fi1.transpose()
- * (Ei1_P * E.block<2, 3>(2 * i2, 0).transpose() * Fi2);
+ * (Ei1_P * E.block(ZDim * i2, 0).transpose() * Fi2);
GsIndex++;
}
} // end of for over cameras
@@ -587,9 +596,9 @@ public:
for (size_t i1 = 0; i1 < numKeys; i1++) { // for each camera in the current factor
const Matrix2D& Fi1 = Fblocks.at(i1).second;
- const Matrix23 Ei1_P = E.block<2, 3>(2 * i1, 0) * P;
+ const Matrix23 Ei1_P = E.block(ZDim * i1, 0) * P;
- // D = (Dx2) * (2)
+ // D = (DxZDim) * (ZDim)
// allKeys are the list of all camera keys in the group, e.g, (1,3,4,5,7)
// we should map those to a slot in the local (grouped) hessian (0,1,2,3,4)
// Key cameraKey_i1 = this->keys_[i1];
@@ -599,15 +608,15 @@ public:
// vectorBlock = augmentedHessian(aug_i1, aug_numKeys).knownOffDiagonal();
// add contribution of current factor
augmentedHessian(aug_i1, aug_numKeys) = augmentedHessian(aug_i1, aug_numKeys).knownOffDiagonal()
- + Fi1.transpose() * b.segment<2>(2 * i1) // F' * b
- - Fi1.transpose() * (Ei1_P * (E.transpose() * b)); // D = (Dx2) * (2x3) * (3*2m) * (2m x 1)
+ + Fi1.transpose() * b.segment(ZDim * i1) // F' * b
+ - Fi1.transpose() * (Ei1_P * (E.transpose() * b)); // D = (DxZDim) * (ZDimx3) * (3*ZDimm) * (ZDimm x 1)
- // (DxD) = (Dx2) * ( (2xD) - (2x3) * (3x2) * (2xD) )
+ // (DxD) = (DxZDim) * ( (ZDimxD) - (ZDimx3) * (3xZDim) * (ZDimxD) )
// main block diagonal - store previous block
matrixBlock = augmentedHessian(aug_i1, aug_i1);
// add contribution of current factor
augmentedHessian(aug_i1, aug_i1) = matrixBlock +
- ( Fi1.transpose() * (Fi1 - Ei1_P * E.block<2, 3>(2 * i1, 0).transpose() * Fi1) );
+ ( Fi1.transpose() * (Fi1 - Ei1_P * E.block(ZDim * i1, 0).transpose() * Fi1) );
// upper triangular part of the hessian
for (size_t i2 = i1 + 1; i2 < numKeys; i2++) { // for each camera
@@ -616,12 +625,12 @@ public:
//Key cameraKey_i2 = this->keys_[i2];
DenseIndex aug_i2 = KeySlotMap[this->keys_[i2]];
- // (DxD) = (Dx2) * ( (2x2) * (2xD) )
+ // (DxD) = (DxZDim) * ( (ZDimxZDim) * (ZDimxD) )
// off diagonal block - store previous block
// matrixBlock = augmentedHessian(aug_i1, aug_i2).knownOffDiagonal();
// add contribution of current factor
augmentedHessian(aug_i1, aug_i2) = augmentedHessian(aug_i1, aug_i2).knownOffDiagonal()
- - Fi1.transpose() * (Ei1_P * E.block<2, 3>(2 * i2, 0).transpose() * Fi2);
+ - Fi1.transpose() * (Ei1_P * E.block(ZDim * i2, 0).transpose() * Fi2);
}
} // end of for over cameras
@@ -641,7 +650,7 @@ public:
}
// ****************************************************************************************************
- boost::shared_ptr > createJacobianQFactor(
+ boost::shared_ptr > createJacobianQFactor(
const Cameras& cameras, const Point3& point, double lambda = 0.0,
bool diagonalDamping = false) const {
std::vector Fblocks;
@@ -650,18 +659,18 @@ public:
Vector b;
computeJacobians(Fblocks, E, PointCov, b, cameras, point, lambda,
diagonalDamping);
- return boost::make_shared >(Fblocks, E, PointCov, b);
+ return boost::make_shared >(Fblocks, E, PointCov, b);
}
// ****************************************************************************************************
boost::shared_ptr createJacobianSVDFactor(
const Cameras& cameras, const Point3& point, double lambda = 0.0) const {
size_t numKeys = this->keys_.size();
- std::vector < KeyMatrix2D > Fblocks;
+ std::vector Fblocks;
Vector b;
- Matrix Enull(2*numKeys, 2*numKeys-3);
+ Matrix Enull(ZDim*numKeys, ZDim*numKeys-3);
computeJacobiansSVD(Fblocks, Enull, b, cameras, point, lambda);
- return boost::make_shared< JacobianFactorSVD<6> >(Fblocks, Enull, b);
+ return boost::make_shared< JacobianFactorSVD<6, ZDim> >(Fblocks, Enull, b);
}
private:
@@ -676,4 +685,7 @@ private:
}
};
+template
+const int SmartFactorBase::ZDim;
+
} // \ namespace gtsam
diff --git a/gtsam/slam/SmartProjectionFactor.h b/gtsam/slam/SmartProjectionFactor.h
index bfd73d9fb..75e4699d9 100644
--- a/gtsam/slam/SmartProjectionFactor.h
+++ b/gtsam/slam/SmartProjectionFactor.h
@@ -19,7 +19,7 @@
#pragma once
-#include "SmartFactorBase.h"
+#include
#include
#include
@@ -61,8 +61,8 @@ enum LinearizationMode {
* SmartProjectionFactor: triangulates point
* TODO: why LANDMARK parameter?
*/
-template
-class SmartProjectionFactor: public SmartFactorBase {
+template
+class SmartProjectionFactor: public SmartFactorBase, D> {
protected:
// Some triangulation parameters
@@ -92,7 +92,7 @@ protected:
typedef boost::shared_ptr SmartFactorStatePtr;
/// shorthand for base class type
- typedef SmartFactorBase Base;
+ typedef SmartFactorBase, D> Base;
double landmarkDistanceThreshold_; // if the landmark is triangulated at a
// distance larger than that the factor is considered degenerate
@@ -102,7 +102,9 @@ protected:
// and the factor is disregarded if the error is large
/// shorthand for this class
- typedef SmartProjectionFactor This;
+ typedef SmartProjectionFactor This;
+
+ static const int ZDim = traits::dimension::value; ///< Measurement dimension
public:
@@ -418,16 +420,16 @@ public:
}
/// create factor
- boost::shared_ptr > createJacobianQFactor(
+ boost::shared_ptr > createJacobianQFactor(
const Cameras& cameras, double lambda) const {
if (triangulateForLinearize(cameras))
return Base::createJacobianQFactor(cameras, point_, lambda);
else
- return boost::make_shared< JacobianFactorQ >(this->keys_);
+ return boost::make_shared< JacobianFactorQ >(this->keys_);
}
/// Create a factor, takes values
- boost::shared_ptr > createJacobianQFactor(
+ boost::shared_ptr > createJacobianQFactor(
const Values& values, double lambda) const {
Cameras myCameras;
// TODO triangulate twice ??
@@ -435,7 +437,7 @@ public:
if (nonDegenerate)
return createJacobianQFactor(myCameras, lambda);
else
- return boost::make_shared< JacobianFactorQ >(this->keys_);
+ return boost::make_shared< JacobianFactorQ >(this->keys_);
}
/// different (faster) way to compute Jacobian factor
@@ -444,7 +446,7 @@ public:
if (triangulateForLinearize(cameras))
return Base::createJacobianSVDFactor(cameras, point_, lambda);
else
- return boost::make_shared< JacobianFactorSVD >(this->keys_);
+ return boost::make_shared< JacobianFactorSVD >(this->keys_);
}
/// Returns true if nonDegenerate
@@ -707,4 +709,7 @@ private:
}
};
+template
+const int SmartProjectionFactor::ZDim;
+
} // \ namespace gtsam
diff --git a/gtsam/slam/SmartProjectionPoseFactor.h b/gtsam/slam/SmartProjectionPoseFactor.h
index f871ab3aa..3b2e2bcbc 100644
--- a/gtsam/slam/SmartProjectionPoseFactor.h
+++ b/gtsam/slam/SmartProjectionPoseFactor.h
@@ -19,7 +19,7 @@
#pragma once
-#include "SmartProjectionFactor.h"
+#include
namespace gtsam {
/**
@@ -37,8 +37,8 @@ namespace gtsam {
* The calibration is known here. The factor only constraints poses (variable dimension is 6)
* @addtogroup SLAM
*/
-template
-class SmartProjectionPoseFactor: public SmartProjectionFactor {
+template
+class SmartProjectionPoseFactor: public SmartProjectionFactor {
protected:
LinearizationMode linearizeTo_; ///< How to linearize the factor (HESSIAN, JACOBIAN_SVD, JACOBIAN_Q)
@@ -48,10 +48,10 @@ protected:
public:
/// shorthand for base class type
- typedef SmartProjectionFactor Base;
+ typedef SmartProjectionFactor Base;
/// shorthand for this class
- typedef SmartProjectionPoseFactor This;
+ typedef SmartProjectionPoseFactor This;
/// shorthand for a smart pointer to a factor
typedef boost::shared_ptr shared_ptr;
diff --git a/gtsam/slam/tests/testRegularImplicitSchurFactor.cpp b/gtsam/slam/tests/testRegularImplicitSchurFactor.cpp
index e96c8101c..29eaf2ac1 100644
--- a/gtsam/slam/tests/testRegularImplicitSchurFactor.cpp
+++ b/gtsam/slam/tests/testRegularImplicitSchurFactor.cpp
@@ -114,7 +114,7 @@ TEST( regularImplicitSchurFactor, addHessianMultiply ) {
// Create JacobianFactor with same error
const SharedDiagonal model;
- JacobianFactorQ<6> jf(Fblocks, E, P, b, model);
+ JacobianFactorQ<6, 2> jf(Fblocks, E, P, b, model);
{ // error
double expectedError = jf.error(xvalues);
@@ -164,7 +164,7 @@ TEST( regularImplicitSchurFactor, addHessianMultiply ) {
}
// Create JacobianFactorQR
- JacobianFactorQR<6> jfq(Fblocks, E, P, b, model);
+ JacobianFactorQR<6, 2> jfq(Fblocks, E, P, b, model);
{
const SharedDiagonal model;
VectorValues yActual = zero;
diff --git a/gtsam/slam/tests/testSmartProjectionPoseFactor.cpp b/gtsam/slam/tests/testSmartProjectionPoseFactor.cpp
index 4e4fde3e4..c2855f09b 100644
--- a/gtsam/slam/tests/testSmartProjectionPoseFactor.cpp
+++ b/gtsam/slam/tests/testSmartProjectionPoseFactor.cpp
@@ -60,8 +60,8 @@ static Key poseKey1(x1);
static Point2 measurement1(323.0, 240.0);
static Pose3 body_P_sensor1(Rot3::RzRyRx(-M_PI_2, 0.0, -M_PI_2), Point3(0.25, -0.10, 1.0));
-typedef SmartProjectionPoseFactor SmartFactor;
-typedef SmartProjectionPoseFactor SmartFactorBundler;
+typedef SmartProjectionPoseFactor SmartFactor;
+typedef SmartProjectionPoseFactor SmartFactorBundler;
void projectToMultipleCameras(
SimpleCamera cam1, SimpleCamera cam2, SimpleCamera cam3, Point3 landmark,
@@ -1202,7 +1202,7 @@ TEST( SmartProjectionPoseFactor, HessianWithRotationDegenerate ){
/* ************************************************************************* */
TEST( SmartProjectionPoseFactor, ConstructorWithCal3Bundler) {
- SmartProjectionPoseFactor factor1(rankTol, linThreshold);
+ SmartProjectionPoseFactor factor1(rankTol, linThreshold);
boost::shared_ptr Kbundler(new Cal3Bundler(500, 1e-3, 1e-3, 1000, 2000));
factor1.add(measurement1, poseKey1, model, Kbundler);
}
diff --git a/gtsam_unstable/examples/SmartProjectionFactorExample.cpp b/gtsam_unstable/examples/SmartProjectionFactorExample.cpp
index 01c2ab3e1..c8a4e7123 100644
--- a/gtsam_unstable/examples/SmartProjectionFactorExample.cpp
+++ b/gtsam_unstable/examples/SmartProjectionFactorExample.cpp
@@ -46,7 +46,7 @@ using namespace gtsam;
int main(int argc, char** argv){
- typedef SmartProjectionPoseFactor SmartFactor;
+ typedef SmartProjectionPoseFactor SmartFactor;
Values initial_estimate;
NonlinearFactorGraph graph;
diff --git a/gtsam_unstable/examples/SmartStereoProjectionFactorExample.cpp b/gtsam_unstable/examples/SmartStereoProjectionFactorExample.cpp
new file mode 100644
index 000000000..f5e59b1b2
--- /dev/null
+++ b/gtsam_unstable/examples/SmartStereoProjectionFactorExample.cpp
@@ -0,0 +1,153 @@
+/* ----------------------------------------------------------------------------
+
+* 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 SmartProjectionFactorExample.cpp
+* @brief A stereo visual odometry example
+* @date May 30, 2014
+* @author Stephen Camp
+* @author Chris Beall
+*/
+
+
+/**
+ * A smart projection factor example based on stereo data, throwing away the
+ * measurement from the right camera
+ * -robot starts at origin
+ * -moves forward, taking periodic stereo measurements
+ * -makes monocular observations of many landmarks
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+using namespace std;
+using namespace gtsam;
+
+int main(int argc, char** argv){
+
+ typedef SmartStereoProjectionPoseFactor SmartFactor;
+
+ bool output_poses = true;
+ bool output_initial_poses = true;
+ string poseOutput("../../../examples/data/optimized_poses.txt");
+ string init_poseOutput("../../../examples/data/initial_poses.txt");
+ Values initial_estimate;
+ NonlinearFactorGraph graph;
+ const noiseModel::Isotropic::shared_ptr model = noiseModel::Isotropic::Sigma(3,1);
+ ofstream pose3Out, init_pose3Out;
+
+ bool add_initial_noise = true;
+
+ string calibration_loc = findExampleDataFile("VO_calibration.txt");
+ string pose_loc = findExampleDataFile("VO_camera_poses_large.txt");
+ string factor_loc = findExampleDataFile("VO_stereo_factors_large.txt");
+
+ //read camera calibration info from file
+ // focal lengths fx, fy, skew s, principal point u0, v0, baseline b
+ cout << "Reading calibration info" << endl;
+ ifstream calibration_file(calibration_loc.c_str());
+
+ double fx, fy, s, u0, v0, b;
+ calibration_file >> fx >> fy >> s >> u0 >> v0 >> b;
+ const Cal3_S2Stereo::shared_ptr K(new Cal3_S2Stereo(fx, fy, s, u0, v0,b));
+
+ cout << "Reading camera poses" << endl;
+ ifstream pose_file(pose_loc.c_str());
+
+ int pose_id;
+ MatrixRowMajor m(4,4);
+ //read camera pose parameters and use to make initial estimates of camera poses
+ while (pose_file >> pose_id) {
+ for (int i = 0; i < 16; i++) {
+ pose_file >> m.data()[i];
+ }
+ if(add_initial_noise){
+ m(1,3) += (pose_id % 10)/10.0;
+ }
+ initial_estimate.insert(Symbol('x', pose_id), Pose3(m));
+ }
+
+ Values initial_pose_values = initial_estimate.filter();
+ if(output_poses){
+ init_pose3Out.open(init_poseOutput.c_str(),ios::out);
+ for(int i = 1; i<=initial_pose_values.size(); i++){
+ init_pose3Out << i << " " << initial_pose_values.at(Symbol('x',i)).matrix().format(Eigen::IOFormat(Eigen::StreamPrecision, 0,
+ " ", " ")) << endl;
+ }
+ }
+
+ // camera and landmark keys
+ size_t x, l;
+
+ // pixel coordinates uL, uR, v (same for left/right images due to rectification)
+ // landmark coordinates X, Y, Z in camera frame, resulting from triangulation
+ double uL, uR, v, X, Y, Z;
+ ifstream factor_file(factor_loc.c_str());
+ cout << "Reading stereo factors" << endl;
+
+ //read stereo measurements and construct smart factors
+
+ SmartFactor::shared_ptr factor(new SmartFactor());
+ size_t current_l = 3; // hardcoded landmark ID from first measurement
+
+ while (factor_file >> x >> l >> uL >> uR >> v >> X >> Y >> Z) {
+
+ if(current_l != l) {
+ graph.push_back(factor);
+ factor = SmartFactor::shared_ptr(new SmartFactor());
+ current_l = l;
+ }
+ factor->add(StereoPoint2(uL,uR,v), Symbol('x',x), model, K);
+ }
+
+ Pose3 first_pose = initial_estimate.at(Symbol('x',1));
+ //constrain the first pose such that it cannot change from its original value during optimization
+ // NOTE: NonlinearEquality forces the optimizer to use QR rather than Cholesky
+ // QR is much slower than Cholesky, but numerically more stable
+ graph.push_back(NonlinearEquality(Symbol('x',1),first_pose));
+
+ LevenbergMarquardtParams params;
+ params.verbosityLM = LevenbergMarquardtParams::TRYLAMBDA;
+ params.verbosity = NonlinearOptimizerParams::ERROR;
+
+ cout << "Optimizing" << endl;
+ //create Levenberg-Marquardt optimizer to optimize the factor graph
+ LevenbergMarquardtOptimizer optimizer = LevenbergMarquardtOptimizer(graph, initial_estimate, params);
+ Values result = optimizer.optimize();
+
+ cout << "Final result sample:" << endl;
+ Values pose_values = result.filter();
+ pose_values.print("Final camera poses:\n");
+
+ if(output_poses){
+ pose3Out.open(poseOutput.c_str(),ios::out);
+ for(int i = 1; i<=pose_values.size(); i++){
+ pose3Out << i << " " << pose_values.at(Symbol('x',i)).matrix().format(Eigen::IOFormat(Eigen::StreamPrecision, 0,
+ " ", " ")) << endl;
+ }
+ cout << "Writing output" << endl;
+ }
+
+ return 0;
+}
diff --git a/gtsam_unstable/nonlinear/Expression-inl.h b/gtsam_unstable/nonlinear/Expression-inl.h
index 58f6de6b4..08dd18ee3 100644
--- a/gtsam_unstable/nonlinear/Expression-inl.h
+++ b/gtsam_unstable/nonlinear/Expression-inl.h
@@ -252,7 +252,7 @@ public:
}
/// Return dimensions for each argument, as a map
- virtual void dims(std::map& map) const {
+ virtual void dims(std::map& map) const {
}
// Return size needed for memory buffer in traceExecution
@@ -324,7 +324,7 @@ public:
}
/// Return dimensions for each argument
- virtual void dims(std::map& map) const {
+ virtual void dims(std::map& map) const {
// get dimension from the chart; only works for fixed dimension charts
map[key_] = traits::dimension::value;
}
@@ -371,7 +371,7 @@ public:
}
/// Return dimensions for each argument
- virtual void dims(std::map& map) const {
+ virtual void dims(std::map& map) const {
map[key_] = traits::dimension::value;
}
@@ -523,7 +523,7 @@ struct GenerateFunctionalNode: Argument, Base {
}
/// Return dimensions for each argument
- virtual void dims(std::map& map) const {
+ virtual void dims(std::map& map) const {
Base::dims(map);
This::expression->dims(map);
}
diff --git a/gtsam_unstable/nonlinear/Expression.h b/gtsam_unstable/nonlinear/Expression.h
index 5e1d425ed..68a79ed6b 100644
--- a/gtsam_unstable/nonlinear/Expression.h
+++ b/gtsam_unstable/nonlinear/Expression.h
@@ -20,17 +20,31 @@
#pragma once
#include "Expression-inl.h"
+#include
#include
+
#include
+#include
+#include
+
+class ExpressionFactorShallowTest;
namespace gtsam {
+// Forward declare
+template class ExpressionFactor;
+
/**
* Expression class that supports automatic differentiation
*/
template
class Expression {
+public:
+
+ /// Define type so we can apply it as a meta-function
+ typedef Expression type;
+
private:
// Paul's trick shared pointer, polymorphic root of entire expression tree
@@ -55,7 +69,7 @@ public:
// Construct a leaf expression, creating Symbol
Expression(unsigned char c, size_t j) :
- root_(new LeafExpression(Symbol(c, j))) {
+ root_(new LeafExpression(Symbol(c, j))) {
}
/// Construct a nullary method expression
@@ -87,8 +101,7 @@ public:
template
Expression(typename BinaryExpression::Function function,
const Expression