19 #ifndef FACTOR_ADDERS_VO_SMART_PROJECTION_FACTOR_ADDER_H_ 
   20 #define FACTOR_ADDERS_VO_SMART_PROJECTION_FACTOR_ADDER_H_ 
   37 template <
typename PoseNodeAdderType>
 
   53                                std::shared_ptr<PoseNodeAdderType> node_adder);
 
   65                                  gtsam::NonlinearFactorGraph& factors) 
final;
 
   69   int AddFactorsUsingDownsampledMeasurements(gtsam::NonlinearFactorGraph& factors) 
const;
 
   75                       gtsam::NonlinearFactorGraph& factors) 
const;
 
   84   void FixSmartFactors(
const gtsam::Values& values, gtsam::NonlinearFactorGraph& factors) 
const;
 
   87   boost::optional<SharedRobustSmartFactor> FixSmartFactorByRemovingIndividualMeasurements(
 
   91   boost::optional<SharedRobustSmartFactor> FixSmartFactorByRemovingMeasurementSequence(
 
   95   boost::optional<SharedRobustSmartFactor> FixedSmartFactor(
 
   96     const gtsam::Values& values, gtsam::PinholePose<gtsam::Cal3_S2>::MeasurementVector& measurements,
 
   97     gtsam::KeyVector& keys) 
const;
 
  101   template <
class Archive>
 
  102   void serialize(Archive& ar, 
const unsigned int file_version) {
 
  103     ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(
Base);
 
  104     ar& BOOST_SERIALIZATION_NVP(node_adder_);
 
  105     ar& BOOST_SERIALIZATION_NVP(params_);
 
  106     ar& BOOST_SERIALIZATION_NVP(feature_tracker_);
 
  109   std::shared_ptr<PoseNodeAdderType> node_adder_;
 
  111   std::shared_ptr<vision_common::SpacedFeatureTracker> feature_tracker_;
 
  115 template <
typename PoseNodeAdderType>
 
  118     : 
Base(params), params_(params), node_adder_(node_adder) {
 
  122 template <
typename PoseNodeAdderType>
 
  124   return *feature_tracker_;
 
  127 template <
typename PoseNodeAdderType>
 
  130   gtsam::NonlinearFactorGraph& factors) {
 
  133   ProcessMeasurements(oldest_allowed_time, newest_allowed_time,
 
  136                         if (!node_adder_->CanAddNode(measurement.
timestamp)) 
return false;
 
  141   feature_tracker_->RemoveOldPoints(oldest_allowed_time);
 
  144   localization_common::DeleteFactors<RobustSmartFactor>(factors);
 
  147   int num_added_factors = 0;
 
  148   num_added_factors = AddFactorsUsingDownsampledMeasurements(factors);
 
  150   if (params_.fix_invalid_factors) FixSmartFactors(node_adder_->nodes().gtsam_values(), factors);
 
  151   return num_added_factors;
 
  154 template <
typename PoseNodeAdderType>
 
  155 int VoSmartProjectionFactorAdder<PoseNodeAdderType>::AddFactorsUsingDownsampledMeasurements(
 
  156   gtsam::NonlinearFactorGraph& factors)
 const {
 
  157   int num_added_factors = 0;
 
  158   const auto spaced_feature_tracks = feature_tracker_->SpacedFeatureTracks();
 
  159   for (
const auto& feature_track : spaced_feature_tracks) {
 
  160     if (num_added_factors >= params_.max_num_factors) 
break;
 
  161     if (ValidTrack(feature_track)) {
 
  162       if (AddSmartFactor(feature_track, factors)) ++num_added_factors;
 
  165   return num_added_factors;
 
  168 template <
typename PoseNodeAdderType>
 
  169 bool VoSmartProjectionFactorAdder<PoseNodeAdderType>::AddSmartFactor(
 
  172   const int num_feature_track_points = feature_track_points.size();
 
  175   const double noise_scale =
 
  176     params_.scale_noise_with_num_points ? params_.noise_scale * num_feature_track_points : params_.noise_scale;
 
  177   const auto noise = gtsam::noiseModel::Isotropic::Sigma(2, noise_scale * params_.cam_noise->sigma());
 
  179     boost::make_shared<RobustSmartFactor>(noise, params_.cam_intrinsics, params_.body_T_cam, params_.smart_factor,
 
  180                                           params_.rotation_only_fallback, params_.robust, params_.huber_k);
 
  182   for (
int i = 0; i < static_cast<int>(feature_track_points.size()); ++i) {
 
  184     const auto& feature_point = feature_track_points[feature_track_points.size() - 1 - i];
 
  185     if (i >= params_.max_num_points_per_factor) 
break;
 
  186     const auto& timestamp = feature_point.timestamp;
 
  188     if (!node_adder_->AddNode(timestamp, factors)) {
 
  189       LogError(
"AddSmartFactor: Failed to add node for timestamp " << std::setprecision(15) << timestamp << 
".");
 
  192     const auto keys = node_adder_->Keys(timestamp);
 
  194       LogError(
"AddSmartFactor: Failed to get keys for timestamp " << std::setprecision(15) << timestamp << 
".");
 
  198     const auto& pose_key = keys[0];
 
  200     smart_factor->add(SmartFactorCamera::Measurement(feature_point.image_point), pose_key);
 
  202   factors.push_back(smart_factor);
 
  206 template <
typename PoseNodeAdderType>
 
  207 bool VoSmartProjectionFactorAdder<PoseNodeAdderType>::ValidTrack(
 
  210   if (
static_cast<int>(feature_track.size()) < params_.min_num_points_per_factor) 
return false;
 
  211   return (average_distance_from_mean >= params_.min_avg_distance_from_mean);
 
  214 template <
typename PoseNodeAdderType>
 
  215 void VoSmartProjectionFactorAdder<PoseNodeAdderType>::FixSmartFactors(
const gtsam::Values& values,
 
  216                                                                       gtsam::NonlinearFactorGraph& factors)
 const {
 
  217   for (
auto& factor : factors) {
 
  219     if (!smart_factor) 
continue;
 
  221     if (smart_factor->measured().size() <= 2) 
continue;
 
  222     const auto point = smart_factor->triangulateSafe(smart_factor->cameras(values));
 
  223     if (point.valid()) 
continue;
 
  226       const auto fixed_smart_factor = FixSmartFactorByRemovingIndividualMeasurements(values, *smart_factor);
 
  227       if (fixed_smart_factor) {
 
  228         factor = *fixed_smart_factor;
 
  235       const auto fixed_smart_factor = FixSmartFactorByRemovingMeasurementSequence(values, *smart_factor);
 
  236       if (fixed_smart_factor) {
 
  237         factor = *fixed_smart_factor;
 
  242     LogDebug(
"SplitSmartFactorsIfNeeded: Failed to fix smart factor");
 
  246 template <
typename PoseNodeAdderType>
 
  247 boost::optional<SharedRobustSmartFactor>
 
  248 VoSmartProjectionFactorAdder<PoseNodeAdderType>::FixSmartFactorByRemovingIndividualMeasurements(
 
  251   const auto original_measurements = smart_factor.measured();
 
  252   const auto original_keys = smart_factor.keys();
 
  253   int measurement_index_to_remove;
 
  255   for (measurement_index_to_remove = original_measurements.size() - 1; measurement_index_to_remove >= 0;
 
  256        --measurement_index_to_remove) {
 
  257     gtsam::PinholePose<gtsam::Cal3_S2>::MeasurementVector measurements_to_add;
 
  258     gtsam::KeyVector keys_to_add;
 
  259     for (
int i = 0; i < static_cast<int>(original_measurements.size()); ++i) {
 
  260       if (i == measurement_index_to_remove) 
continue;
 
  261       measurements_to_add.emplace_back(original_measurements[i]);
 
  262       keys_to_add.emplace_back(original_keys[i]);
 
  264     const auto fixed_smart_factor = FixedSmartFactor(values, measurements_to_add, keys_to_add);
 
  265     if (fixed_smart_factor) {
 
  266       LogDebug(
"FixSmartFactorByRemovingIndividualMeasurements: Fixed by removing measurement " 
  267                << measurement_index_to_remove << 
", num original measurements: " << original_measurements.size());
 
  268       return fixed_smart_factor;
 
  274 template <
typename PoseNodeAdderType>
 
  275 boost::optional<SharedRobustSmartFactor>
 
  276 VoSmartProjectionFactorAdder<PoseNodeAdderType>::FixSmartFactorByRemovingMeasurementSequence(
 
  278   constexpr 
int min_num_measurements = 2;
 
  280   const auto original_measurements = smart_factor.measured();
 
  281   const auto original_keys = smart_factor.keys();
 
  282   int num_measurements_to_add = original_measurements.size() - 1;
 
  284   while (num_measurements_to_add >= min_num_measurements) {
 
  285     gtsam::PinholePose<gtsam::Cal3_S2>::MeasurementVector measurements_to_add;
 
  286     gtsam::KeyVector keys_to_add;
 
  287     for (
int i = 0; i < num_measurements_to_add; ++i) {
 
  288       measurements_to_add.emplace_back(original_measurements[i]);
 
  289       keys_to_add.emplace_back(original_keys[i]);
 
  291     const auto fixed_smart_factor = FixedSmartFactor(values, measurements_to_add, keys_to_add);
 
  292     if (fixed_smart_factor) {
 
  294         "FixSmartFactorByRemovingMeasurementSequence: Fixed smart factor by removing most recent " 
  295         "measurements. Original " 
  297         << original_measurements.size() << 
", new size: " << num_measurements_to_add);
 
  298       return fixed_smart_factor;
 
  300       --num_measurements_to_add;
 
  303   num_measurements_to_add = original_measurements.size() - 1;
 
  305   while (num_measurements_to_add >= min_num_measurements) {
 
  306     gtsam::PinholePose<gtsam::Cal3_S2>::MeasurementVector measurements_to_add;
 
  307     gtsam::KeyVector keys_to_add;
 
  308     for (
int i = original_measurements.size() - num_measurements_to_add;
 
  309          i < 
static_cast<int>(original_measurements.size()); ++i) {
 
  310       measurements_to_add.emplace_back(original_measurements[i]);
 
  311       keys_to_add.emplace_back(original_keys[i]);
 
  313     const auto fixed_smart_factor = FixedSmartFactor(values, measurements_to_add, keys_to_add);
 
  314     if (fixed_smart_factor) {
 
  316         "FixSmartFactorByRemovingMeasurementSequence: Fixed smart factor by removing oldest measurements. " 
  319         << original_measurements.size() << 
", new size: " << num_measurements_to_add);
 
  320       return fixed_smart_factor;
 
  322       --num_measurements_to_add;
 
  331 template <
typename PoseNodeAdderType>
 
  332 boost::optional<SharedRobustSmartFactor> VoSmartProjectionFactorAdder<PoseNodeAdderType>::FixedSmartFactor(
 
  333   const gtsam::Values& values, gtsam::PinholePose<gtsam::Cal3_S2>::MeasurementVector& measurements,
 
  334   gtsam::KeyVector& keys)
 const {
 
  335   auto new_smart_factor = boost::make_shared<RobustSmartFactor>(
 
  336     params_.cam_noise, params_.cam_intrinsics, params_.body_T_cam, params_.smart_factor, params_.rotation_only_fallback,
 
  337     params_.robust, params_.huber_k);
 
  338   new_smart_factor->add(measurements, keys);
 
  339   const auto new_point = new_smart_factor->triangulateSafe(new_smart_factor->cameras(values));
 
  340   if (!new_point.valid()) 
return boost::none;
 
  341   return new_smart_factor;
 
  344 #endif  // FACTOR_ADDERS_VO_SMART_PROJECTION_FACTOR_ADDER_H_