diff --git a/include/core/processor/processor_landmark_external.h b/include/core/processor/processor_landmark_external.h index 6e4ba1f4167de4c4189dea87621b02c474aae5bf..5c574a6e9a3a0a8c94254329dfaaa766be5f8db4 100644 --- a/include/core/processor/processor_landmark_external.h +++ b/include/core/processor/processor_landmark_external.h @@ -33,11 +33,12 @@ WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorLandmarkExternal); struct ParamsProcessorLandmarkExternal : public ParamsProcessorTracker { - bool use_orientation; ///< use orientation measure or not when emplacing factors - double filter_quality_th; ///< min quality to consider the detection - double filter_dist_th; ///< for considering tracked detection: distance threshold to previous detection - unsigned int filter_track_length_th; ///< length of the track necessary to consider the detection - double time_span; ///< for keyframe voting: time span since last frame + bool use_orientation; ///< use orientation measure or not when emplacing factors + double match_dist_th; ///< for considering tracked detection: distance threshold to previous detection + unsigned int new_features_for_keyframe; ///< for keyframe voting: amount of new features with respect to origin (sufficient condition if more than min_features_for_keyframe) + double filter_quality_th; ///< min quality to consider the detection + unsigned int filter_track_length_th; ///< length of the track necessary to consider the detection + double time_span; ///< for keyframe voting: time span since last frame (sufficient condition if more than min_features_for_keyframe) ParamsProcessorLandmarkExternal() = default; ParamsProcessorLandmarkExternal(std::string _unique_name, @@ -45,9 +46,9 @@ struct ParamsProcessorLandmarkExternal : public ParamsProcessorTracker ParamsProcessorTracker(_unique_name, _server) { use_orientation = _server.getParam<bool> (prefix + _unique_name + "/use_orientation"); - filter_quality_th = _server.getParam<double> (prefix + _unique_name + "/filter_quality_th"); - filter_dist_th = _server.getParam<double> (prefix + _unique_name + "/filter_dist_th"); - filter_track_length_th = _server.getParam<unsigned int>(prefix + _unique_name + "/filter_track_length_th"); + filter_quality_th = _server.getParam<double> (prefix + _unique_name + "/filter/quality_th"); + filter_track_length_th = _server.getParam<unsigned int>(prefix + _unique_name + "/filter/track_length_th"); + match_dist_th = _server.getParam<double> (prefix + _unique_name + "/match_dist_th"); time_span = _server.getParam<double> (prefix + _unique_name + "/keyframe_vote/time_span"); } }; @@ -70,6 +71,7 @@ class ProcessorLandmarkExternal : public ProcessorTracker ParamsProcessorLandmarkExternalPtr params_tfle_; TrackMatrix track_matrix_; + std::set<SizeStd> lmks_ids_origin_; /** Pre-process incoming Capture * @@ -143,7 +145,8 @@ class ProcessorLandmarkExternal : public ProcessorTracker inline ProcessorLandmarkExternal::ProcessorLandmarkExternal(ParamsProcessorLandmarkExternalPtr _params_tfle) : ProcessorTracker("ProcessorLandmarkExternal", "PO", 0, _params_tfle), - params_tfle_(_params_tfle) + params_tfle_(_params_tfle), + lmks_ids_origin_() { // } diff --git a/src/processor/processor_landmark_external.cpp b/src/processor/processor_landmark_external.cpp index 63adbb9265f01d1e13a8520524025c8059ee7e25..2ac3ff66ae6d3ed22787b7b8166cf9c4c5b8965a 100644 --- a/src/processor/processor_landmark_external.cpp +++ b/src/processor/processor_landmark_external.cpp @@ -116,7 +116,7 @@ unsigned int ProcessorLandmarkExternal::processKnown() while (feat_candidate_it != new_features_incoming_.end()) { if ((*feat_candidate_it)->landmarkId() == feat_last->landmarkId() and - detectionDistance(feat_last, (*feat_candidate_it), pose_in, pose_out, pose_sen) < params_tfle_->filter_dist_th) + detectionDistance(feat_last, (*feat_candidate_it), pose_in, pose_out, pose_sen) < params_tfle_->match_dist_th) { // grow track track_matrix_.add(feat_last, *feat_candidate_it); @@ -197,33 +197,46 @@ bool ProcessorLandmarkExternal::voteForKeyFrame() const { auto track_ids_last = track_matrix_.trackIds(last_ptr_); - WOLF_INFO("Nbr. of active feature tracks: " , track_ids_last.size() ); + WOLF_INFO("Active feature tracks: " , track_ids_last.size() ); // no tracks longer than filter_track_length_th auto n_tracks = 0; + auto n_new_tracks = 0; for (auto track_id : track_ids_last) { if (track_matrix_.trackSize(track_id) >= params_tfle_->filter_track_length_th) + { n_tracks++; + if (not lmks_ids_origin_.count(track_matrix_.feature(track_id, last_ptr_)->landmarkId())) + n_new_tracks++; + } } - WOLF_INFO("Nbr. of active feature tracks (longer than ", params_tfle_->filter_track_length_th, "): " , n_tracks ); - if (n_tracks == 0) - return false; - - auto matches_origin_last = track_matrix_.matches(origin_ptr_, last_ptr_); - bool vote = false;// = n_tracks < params_tracker_feature_->min_features_for_keyframe; - - if (origin_ptr_) + + // Necessary condition: active valid tracks + bool vote_min_features = n_tracks >= params_tfle_->min_features_for_keyframe; + WOLF_INFO("vote_min_features: ", vote_min_features, + " - Active feature tracks longer than ", params_tfle_->filter_track_length_th, ": ", n_tracks, + " (should be equal or bigger than ", params_tfle_->min_features_for_keyframe, ")"); + + bool vote_new_features(true), vote_time_span(true); + if (vote_min_features and origin_ptr_) { - WOLF_INFO("Time span since last frame: " , - last_ptr_->getTimeStamp() - origin_ptr_->getTimeStamp() , - " (should be greater than ", - params_tfle_->time_span, - ")"); - vote = vote or last_ptr_->getTimeStamp() - origin_ptr_->getTimeStamp() > params_tfle_->time_span; + // Sufficient condition: new valid tracks + vote_new_features = n_new_tracks >= params_tfle_->new_features_for_keyframe; + WOLF_INFO("vote_new_features: " , vote_new_features, + " - n_new_tracks = ", n_new_tracks, + " (should be equal or bigger than ", params_tfle_->new_features_for_keyframe, ")"); + + // Sufficient condition: time span + vote_time_span = last_ptr_->getTimeStamp() - origin_ptr_->getTimeStamp() > params_tfle_->time_span; + WOLF_INFO("vote_time_span: " , vote_time_span, + " - time_span = ", last_ptr_->getTimeStamp() - origin_ptr_->getTimeStamp(), + " (should be bigger than ", params_tfle_->time_span, ")"); } - WOLF_INFO( (vote ? "Vote ": "Do not vote ") , "for KF" ); + bool vote = vote_min_features and (vote_new_features or vote_time_span); + + WOLF_INFO( (vote ? "Vote ": "Do NOT vote ") , "for KF" ); return vote; } @@ -233,6 +246,8 @@ void ProcessorLandmarkExternal::establishFactors() if (origin_ptr_ == last_ptr_) return; + // reset n_tracks_origin_ + lmks_ids_origin_.clear(); // will emplace a factor (and landmark if needed) for each known feature in last with long tracks (params_tfle_->filter_track_length_th) FactorBasePtrList fac_list; @@ -259,6 +274,8 @@ void ProcessorLandmarkExternal::establishFactors() // emplace factor auto fac = emplaceFactor(feature, lmk); + lmks_ids_origin_.insert(lmk->id()); + if (fac) fac_list.push_back(fac); } @@ -459,171 +476,6 @@ void ProcessorLandmarkExternal::modifyLandmark(LandmarkBasePtr _landmark, throw std::runtime_error("ProcessorLandmarkExternal::modifyLandmark unknown case"); } -// FactorBasePtr ProcessorLandmarkExternal::emplaceFactor(FeatureBasePtr _feature, -// FeatureBasePtr _feature_other_ptr) -// { -// assert(_feature); -// assert(_feature_other_ptr); -// assert(_feature->getCapture()); -// assert(_feature->getCapture()->getFrame()); - -// assert(getProblem()); -// assert(getProblem()->getMap()); - -// // Check track length -// if (params_tfle_->filter_track_length_th > 1) -// { -// auto snapshot = track_matrix_.snapshot(_feature->getCapture()); -// const auto& it = std::find_if(snapshot.begin(), snapshot.end(), -// [_feature](const std::pair<SizeStd, FeatureBasePtr>& pair) -// { -// return pair.second == _feature; -// }); -// assert(it != snapshot.end()); -// if (track_matrix_.track(it->first).size() < params_tfle_->filter_track_length_th) -// return nullptr; -// } - -// // Get landmark -// LandmarkBasePtr lmk = getProblem()->getMap()->getLandmark(_feature->landmarkId()); - -// // 2D - Relative Position -// if (getProblem()->getDim() == 2 and (_feature->getMeasurement().size() == 2 or not params_tfle_->use_orientation)) -// { -// // no landmark, create it -// if (not lmk) -// { -// Vector2d frm_p = _feature->getCapture()->getFrame()->getP()->getState(); -// Vector2d sen_p = _feature->getCapture()->getSensorP()->getState(); -// double frm_o = _feature->getCapture()->getFrame()->getO()->getState()(0); -// double sen_o = _feature->getCapture()->getSensorO()->getState()(0); - -// Vector2d lmk_p = frm_p + Rotation2Dd(frm_o) * (sen_p + Rotation2Dd(sen_o) * _feature->getMeasurement()); - -// lmk = LandmarkBase::emplace<LandmarkBase>(getProblem()->getMap(), -// "LandmarkRelativePosition2d", -// std::make_shared<StatePoint2d>(lmk_p), -// nullptr); -// lmk->setId(_feature->landmarkId()); -// } - -// // emplace factor -// return FactorBase::emplace<FactorRelativePosition2dWithExtrinsics>(_feature, -// _feature, -// lmk, -// shared_from_this(), -// params_tfle_->apply_loss_function); -// } -// // 2D - Relative Pose -// else if (getProblem()->getDim() == 2 and _feature->getMeasurement().size() == 3 and params_tfle_->use_orientation) -// { -// // no landmark, create it -// if (not lmk) -// { -// Vector2d frm_p = _feature->getCapture()->getFrame()->getP()->getState(); -// Vector2d sen_p = _feature->getCapture()->getSensorP()->getState(); -// double frm_o = _feature->getCapture()->getFrame()->getO()->getState()(0); -// double sen_o = _feature->getCapture()->getSensorO()->getState()(0); - -// Vector2d lmk_p = frm_p + Rotation2Dd(frm_o) * (sen_p + Rotation2Dd(sen_o) * _feature->getMeasurement().head<2>()); -// double lmk_o = frm_o + sen_o + _feature->getMeasurement()(2); - -// lmk = LandmarkBase::emplace<LandmarkBase>(getProblem()->getMap(), -// "LandmarkRelativePose2d", -// std::make_shared<StatePoint2d>(lmk_p), -// std::make_shared<StateAngle>(lmk_o)); -// lmk->setId(_feature->landmarkId()); -// } -// // no orientation, add it -// else if (not lmk->getO()) -// { -// double frm_o = _feature->getCapture()->getFrame()->getO()->getState()(0); -// double sen_o = _feature->getCapture()->getSensorO()->getState()(0); - -// double lmk_o = frm_o + sen_o + _feature->getMeasurement()(2); - -// lmk->addStateBlock('O', std::make_shared<StateAngle>(lmk_o), getProblem()); -// } - -// // emplace factor -// return FactorBase::emplace<FactorRelativePose2dWithExtrinsics>(_feature, -// _feature, -// lmk, -// shared_from_this(), -// params_tfle_->apply_loss_function); -// } -// // 3D - Relative Position -// else if (getProblem()->getDim() == 3 and (_feature->getMeasurement().size() == 3 or not params_tfle_->use_orientation)) -// { -// // no landmark, create it -// if (not lmk) -// { -// Vector3d frm_p = _feature->getCapture()->getFrame()->getP()->getState(); -// Vector3d sen_p = _feature->getCapture()->getSensorP()->getState(); -// Quaterniond frm_o = Quaterniond(Vector4d(_feature->getCapture()->getFrame()->getO()->getState())); -// Quaterniond sen_o = Quaterniond(Vector4d(_feature->getCapture()->getSensorO()->getState())); - -// Vector3d lmk_p = frm_p + frm_o * (sen_p + sen_o * _feature->getMeasurement()); - -// lmk = LandmarkBase::emplace<LandmarkBase>(getProblem()->getMap(), -// "LandmarkRelativePosition3d", -// std::make_shared<StatePoint3d>(lmk_p), -// nullptr); -// lmk->setId(_feature->landmarkId()); -// } - -// // emplace factor -// return FactorBase::emplace<FactorRelativePosition3dWithExtrinsics>(_feature, -// _feature, -// lmk, -// shared_from_this(), -// params_tfle_->apply_loss_function); -// } -// // 3D - Relative Pose -// else if (getProblem()->getDim() == 3 and _feature->getMeasurement().size() == 7 and params_tfle_->use_orientation) -// { -// // no landmark, create it -// if (not lmk) -// { -// Vector3d frm_p = _feature->getCapture()->getFrame()->getP()->getState(); -// Vector3d sen_p = _feature->getCapture()->getSensorP()->getState(); -// Quaterniond frm_o = Quaterniond(Vector4d(_feature->getCapture()->getFrame()->getO()->getState())); -// Quaterniond sen_o = Quaterniond(Vector4d(_feature->getCapture()->getSensorO()->getState())); - -// Vector3d lmk_p = frm_p + frm_o * (sen_p + sen_o * _feature->getMeasurement().head<3>()); -// Quaterniond lmk_o = frm_o * sen_o * Quaterniond(_feature->getMeasurement().tail<4>()); - -// lmk = LandmarkBase::emplace<LandmarkBase>(getProblem()->getMap(), -// "LandmarkRelativePose3d", -// std::make_shared<StatePoint3d>(lmk_p), -// std::make_shared<StateQuaternion>(lmk_o)); -// lmk->setId(_feature->landmarkId()); -// } -// // no orientation, add it -// else if (not lmk->getO()) -// { -// Quaterniond frm_o = Quaterniond(Vector4d(_feature->getCapture()->getFrame()->getO()->getState())); -// Quaterniond sen_o = Quaterniond(Vector4d(_feature->getCapture()->getSensorO()->getState())); - -// Quaterniond lmk_o = frm_o * sen_o * Quaterniond(_feature->getMeasurement().tail<4>()); - -// lmk->addStateBlock('O', std::make_shared<StateQuaternion>(lmk_o), getProblem()); -// } - -// // emplace factor -// return FactorBase::emplace<FactorRelativePose3dWithExtrinsics>(_feature, -// _feature, -// lmk, -// shared_from_this(), -// params_tfle_->apply_loss_function); -// } -// else -// throw std::runtime_error("ProcessorLandmarkExternal::emplaceFactor unknown case"); - -// // not reachable -// return nullptr; -// } - void ProcessorLandmarkExternal::advanceDerived() { // Reset here the list of correspondences. diff --git a/test/gtest_processor_landmark_external.cpp b/test/gtest_processor_landmark_external.cpp index d061cd04c091ab88fd323de80a1e59e76eb0138c..201e8f61a26fe70aac63d99365668ea3cc2968c0 100644 --- a/test/gtest_processor_landmark_external.cpp +++ b/test/gtest_processor_landmark_external.cpp @@ -82,12 +82,12 @@ class ProcessorLandmarkExternalTest : public testing::Test }; void ProcessorLandmarkExternalTest::initProblem(int _dim, - bool _orientation, - double _quality_th, - double _dist_th, - unsigned int _track_length_th, - double _time_span, - bool _add_landmarks) + bool _orientation, + double _quality_th, + double _dist_th, + unsigned int _track_length_th, + double _time_span, + bool _add_landmarks) { dim = _dim; orientation = _orientation; @@ -132,7 +132,9 @@ void ProcessorLandmarkExternalTest::initProblem(int _dim, params->apply_loss_function = false; params->use_orientation = orientation; params->filter_quality_th = _quality_th; - params->filter_dist_th = _dist_th; + params->match_dist_th = _dist_th; + params->min_features_for_keyframe = 1; + params->new_features_for_keyframe = 1000; params->filter_track_length_th = _track_length_th; params->time_span = _time_span; processor = ProcessorBase::emplace<ProcessorLandmarkExternal>(sensor, params);