class LocalImageFramePointLandmarkProjectionFactor
: public gtsam::NoiseModelFactor2<gtsam::Pose3, gtsam::Pose3> {
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
public:
typedef gtsam::NoiseModelFactor2<gtsam::Pose3, gtsam::Pose3> Base;
typedef LocalImageFramePointLandmarkProjectionFactor This;
typedef boost::shared_ptr<This> shared_ptr;
// point_i : observed point uv. (of image_b)
// point_I : 3d point in imu frame of reference (of image_a)
// model : Noise Model aka sigma
// K : camera intrinsic
// T_I_C : pose of camera in imu frame of reference
LocalImageFramePointLandmarkProjectionFactor(
gtsam::Key key_a, gtsam::Key key_b, const gtsam::Point2 &point_i,
const gtsam::Point3 &point_C, const gtsam::SharedNoiseModel &model,
const boost::shared_ptr<gtsam::Cal3_S2> &K,
gtsam::Pose3 T_I_C = gtsam::Pose3())
: Base(model, key_a, key_b),
point_i_(point_i),
point_C_(point_C),
K_(K),
T_I_C_(T_I_C) {
// T_C_I_ = T_I_C_.inverse();
}
virtual ~LocalImageFramePointLandmarkProjectionFactor() override {}
virtual gtsam::NonlinearFactor::shared_ptr clone() const override {
return boost::static_pointer_cast<gtsam::NonlinearFactor>(
gtsam::NonlinearFactor::shared_ptr(new This(*this)));
}
/// Evaluate error h(x)-z and optionally derivatives
gtsam::Vector evaluateError(
const gtsam::Pose3 &T_G_Ia, const gtsam::Pose3 &T_G_Ib,
boost::optional<gtsam::Matrix &> H1 = boost::none,
boost::optional<gtsam::Matrix &> H2 = boost::none) const override {
if (H1) {
*H1 = gtsam::zeros(2, 6);
*H2 = gtsam::zeros(2, 6);
}
try {
if( H1 ) {
gtsam::Matrix D_TGCa_TGIa, D_TGCb_TGIb;
gtsam::Pose3 T_G_Ca = T_G_Ia.compose( T_I_C_, D_TGCa_TGIa );
gtsam::Pose3 T_G_Cb = T_G_Ib.compose( T_I_C_, D_TGCb_TGIb );
gtsam::Matrix D_betweenpose_TGCa, D_betweenpose_TGCb;
gtsam::Pose3 T_Cb_Ca = T_G_Cb.between( T_G_Ca, D_betweenpose_TGCb, D_betweenpose_TGCa );
gtsam::Matrix D_campose;
gtsam::PinholeCamera<gtsam::Cal3_S2> camera( T_Cb_Ca, *K_);
gtsam::Point2 _projected_pt = camera.project(point_C_, D_campose );
*H1 = D_campose * D_betweenpose_TGCa * D_TGCa_TGIa;
*H2 = D_campose * D_betweenpose_TGCb * D_TGCb_TGIb;
return (_projected_pt - point_i_);
}else {
gtsam::Pose3 T_G_Ca = T_G_Ia.compose( T_I_C_ );
gtsam::Pose3 T_G_Cb = T_G_Ib.compose( T_I_C_ );
gtsam::Pose3 T_Cb_Ca = T_G_Cb.between( T_G_Ca );
gtsam::PinholeCamera<gtsam::Cal3_S2> camera( T_Cb_Ca, *K_);
gtsam::Point2 residuals =
camera.project(point_C_) - point_i_;
return residuals.vector();
}
} catch (gtsam::CheiralityException &e) {
// LOG(FATAL) << "Landmark moved behind camera "
// << gtsam::DefaultKeyFormatter(this->key() );
}
// This only gets called in case a cheirality exc was thrown,
// error handling from GTSAM's ProjectionFactor.h
return gtsam::ones(2) * 2.0 * K_->fx();
}
private:
gtsam::Point2 point_i_; //< observed point uv. (of image_b)
gtsam::Point3 point_C_; //< 3d point in camera frame of reference (of image_a)
boost::shared_ptr<gtsam::Cal3_S2> K_;
gtsam::Pose3 T_I_C_;
// gtsam::Pose3 T_C_I_;
public:
};
} // namespace graph_optimization