19 #ifndef GRAPH_FACTORS_ROBUST_SMART_PROJECTION_POSE_FACTOR_H_
20 #define GRAPH_FACTORS_ROBUST_SMART_PROJECTION_POSE_FACTOR_H_
24 #include <gtsam/slam/SmartProjectionPoseFactor.h>
30 template <
class CALIBRATION>
32 typedef PinholePose<CALIBRATION> Camera;
33 typedef SmartFactorBase<Camera> Base;
34 typedef typename Camera::Measurement Z;
35 static const int Dim = traits<Camera>::dimension;
36 static const int ZDim = traits<Z>::dimension;
49 const boost::optional<Pose3> body_P_sensor,
50 const SmartProjectionParams& params = SmartProjectionParams(),
51 const bool rotation_only_fallback =
false,
const bool robust =
true,
52 const double huber_k = 1.0)
53 : SmartProjectionPoseFactor<CALIBRATION>(sharedNoiseModel, K, body_P_sensor, params),
54 sharedNoiseModel_(sharedNoiseModel),
56 rotation_only_fallback_(rotation_only_fallback),
60 if (!sharedNoiseModel)
throw std::runtime_error(
"RobustSmartProjectionPoseFactor: sharedNoiseModel is required");
61 SharedIsotropic sharedIsotropic = boost::dynamic_pointer_cast<noiseModel::Isotropic>(sharedNoiseModel);
62 if (!sharedIsotropic)
throw std::runtime_error(
"RobustSmartProjectionPoseFactor: needs isotropic");
63 noise_inv_sigma_ = 1.0 / sharedIsotropic->sigma();
64 triangulation_params_ = params.triangulation;
68 boost::shared_ptr<NonlinearFactor>
PrunedCopy(
const std::unordered_set<gtsam::Key>& keys_to_remove)
const final {
69 boost::shared_ptr<RobustSmartProjectionPoseFactor> pruned_factor(
71 rotation_only_fallback_, robust_, huber_k_));
72 for (
int i = 0; i < this->keys().size(); ++i) {
73 if (keys_to_remove.count(this->keys()[i]) == 0) pruned_factor->add(this->measured()[i], this->keys()[i]);
76 if (pruned_factor->measured().size() < 2)
return nullptr;
80 boost::shared_ptr<GaussianFactor>
linearize(
const Values& values)
const override {
81 typename Base::Cameras cameras = this->cameras(values);
83 const auto result = this->triangulateSafe(cameras);
85 size_t m = this->keys().size();
86 typename Base::FBlocks F;
88 const size_t M = ZDim * m;
94 this->computeJacobiansSVD(F, E0, b, cameras, *(this->point()));
96 Unit3 backProjected = cameras[0].backprojectPointAtInfinity(this->measured().at(0));
99 this->computeJacobiansSVD(F, E0, b, cameras, backProjected);
101 return boost::make_shared<JacobianFactorSVD<Dim, 2>>(this->keys());
104 return boost::make_shared<JacobianFactorSVD<Dim, 2>>(this->keys());
106 return createRegularJacobianFactorSVD<Dim, ZDim>(this->keys(), F, E0, b);
114 double error(
const Values& values)
const override {
115 if (this->active(values)) {
117 const double total_reprojection_loss = this->totalReprojectionError(this->cameras(values));
118 const auto result = this->point();
122 const double loss = robust_ ?
robustLoss(2.0 * total_reprojection_loss) : total_reprojection_loss;
137 if (this->active(values)) {
140 const double total_reprojection_loss = this->totalReprojectionError(this->cameras(values), point);
144 const double loss = robust_ ?
robustLoss(2.0 * total_reprojection_loss) : total_reprojection_loss;
156 return gtsam::triangulateSafe(this->cameras(values), this->measured(), triangulation_params_);
165 const double sqrt_mahal_distance = std::sqrt(mahal_distance);
166 const double absError = std::abs(sqrt_mahal_distance);
167 if (absError <= huber_k_) {
168 return mahal_distance / 2;
170 return huber_k_ * (absError - (huber_k_ / 2));
174 bool valid(
const Values& values)
const {
175 typename Base::Cameras cameras = this->cameras(values);
176 const auto point = this->triangulateSafe(cameras);
180 Unit3 backProjected = cameras[0].backprojectPointAtInfinity(this->measured().at(0));
182 cameras.reprojectionError(backProjected, this->measured());
195 template <
size_t D,
size_t ZDim>
196 boost::shared_ptr<RegularJacobianFactor<D>> createRegularJacobianFactorSVD(
197 const KeyVector& keys,
198 const std::vector<Eigen::Matrix<double, ZDim, D>, Eigen::aligned_allocator<Eigen::Matrix<double, ZDim, D>>>&
200 const Matrix& Enull,
const Vector& b)
const {
201 typedef std::pair<Key, Matrix> KeyMatrix;
203 Vector reduced_error = Enull.transpose() * b;
207 reduced_error *= noise_inv_sigma_;
208 double reduced_matrix_weight = noise_inv_sigma_;
210 const double robust_weight = robustWeight(reduced_error.norm());
211 reduced_error *= robust_weight;
212 reduced_matrix_weight *= robust_weight;
215 size_t numKeys = Enull.rows() / ZDim;
216 size_t m2 = Enull.cols();
217 std::vector<KeyMatrix> reduced_matrices;
218 reduced_matrices.reserve(numKeys);
219 for (
size_t k = 0; k < Fblocks.size(); ++k) {
221 reduced_matrices.emplace_back(
222 KeyMatrix(key, (Enull.transpose()).block(0, ZDim * k, m2, ZDim) * Fblocks[k] * reduced_matrix_weight));
225 return boost::make_shared<RegularJacobianFactor<D>>(reduced_matrices, reduced_error);
230 double robustWeight(
const double error_norm)
const {
231 const double squared_weight = (error_norm <= huber_k_) ? (1.0) : (huber_k_ / error_norm);
232 return std::sqrt(squared_weight);
237 template <
class ARCHIVE>
238 void serialize(ARCHIVE& ar,
const unsigned int ) {
239 ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(SmartProjectionPoseFactor<CALIBRATION>);
240 ar& BOOST_SERIALIZATION_NVP(noise_inv_sigma_);
241 ar& BOOST_SERIALIZATION_NVP(huber_k_);
242 ar& BOOST_SERIALIZATION_NVP(robust_);
243 ar& BOOST_SERIALIZATION_NVP(rotation_only_fallback_);
244 ar& BOOST_SERIALIZATION_NVP(triangulation_params_);
247 bool rotation_only_fallback_;
250 double noise_inv_sigma_;
252 TriangulationParameters triangulation_params_;
254 SharedNoiseModel sharedNoiseModel_;
255 SmartProjectionParams params_;
259 #endif // GRAPH_FACTORS_ROBUST_SMART_PROJECTION_POSE_FACTOR_H_