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_