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_