16 #include <mrpt/otherlibs/do_opencv_includes.h>
33 template <
typename FEATLIST>
35 FEATLIST& featureList,
const CImage& cur_gray,
36 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
37 const unsigned int max_x,
const unsigned int max_y);
42 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
43 const unsigned int max_x,
const unsigned int max_y)
47 itFeat != itFeatEnd; ++itFeat)
53 const unsigned int x = ft->
x;
54 const unsigned int y = ft->
y;
55 if (
x > KLT_response_half_win &&
y > KLT_response_half_win &&
56 x < max_x &&
y < max_y)
62 if (ft->
response < minimum_KLT_response)
75 template <
class FEAT_LIST>
77 FEAT_LIST& featureList,
const CImage& cur_gray,
78 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
79 const unsigned int max_x_,
const unsigned int max_y_)
81 if (featureList.empty())
return;
83 using pixel_coord_t =
typename FEAT_LIST::feature_t::pixel_coord_t;
84 const pixel_coord_t half_win =
85 static_cast<pixel_coord_t
>(KLT_response_half_win);
86 const pixel_coord_t max_x =
static_cast<pixel_coord_t
>(max_x_);
87 const pixel_coord_t max_y =
static_cast<pixel_coord_t
>(max_y_);
89 for (
int N = featureList.size() - 1; N >= 0; --N)
91 typename FEAT_LIST::feature_t& ft = featureList[N];
95 if (ft.pt.x > half_win && ft.pt.y > half_win && ft.pt.x < max_x &&
99 cur_gray.
KLT_response(ft.pt.x, ft.pt.y, KLT_response_half_win);
103 if (ft.response < minimum_KLT_response)
119 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
120 const unsigned int max_x,
const unsigned int max_y)
122 trackFeatures_checkResponses_impl_simple<TSimpleFeatureList>(
123 featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
129 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
130 const unsigned int max_x,
const unsigned int max_y)
132 trackFeatures_checkResponses_impl_simple<TSimpleFeaturefList>(
133 featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
137 template <
typename FEATLIST>
139 FEATLIST& featureList,
const CImage& cur_gray);
146 itFeat != featureList.
end(); ++itFeat)
154 if (patch_width > 0 && patch_height > 0)
158 const int offset = (int)patch_width / 2;
161 patch_width, patch_height);
163 catch (std::exception&)
187 template <
typename FEATLIST>
190 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
191 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
192 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
198 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
199 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
200 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
204 const int offset = (int)patchSize / 2 + 1;
205 const int w_off = int(imgSize.
x -
offset);
206 const int h_off = int(imgSize.
y -
offset);
208 for (
size_t i = 0; i < nNewToCheck && featureList.
size() < maxNumFeatures;
213 if (feat.
response < minimum_KLT_response_to_add)
continue;
215 double min_dist_sqr =
square(10000);
217 if (!featureList.
empty())
227 if (min_dist_sqr > threshold_sqr_dist_to_add_new &&
234 ft->ID = ++max_feat_ID_at_input;
240 ft->patchSize = patchSize;
253 template <
class FEAT_LIST>
256 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
257 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
258 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
263 const int max_manhatan_dist = std::sqrt(2*threshold_sqr_dist_to_add_new);
265 for (
size_t i=0;i<nNewToCheck && featureList.size()<maxNumFeatures;i++)
268 if (feat.
response<minimum_KLT_response_to_add)
break;
271 int manh_dist = std::numeric_limits<int>::max();
272 for (
size_t j=0;j<featureList.size();j++)
275 const int d = std::abs(existing.
pt.x-feat.
pt.x)+std::abs(existing.
pt.y-feat.
pt.y);
279 if (manh_dist<max_manhatan_dist)
283 featureList.push_back_fast(feat.
pt.x,feat.
pt.y);
289 newFeat.
ID = ++max_feat_ID_at_input;
297 const int grid_cell_log2 =
round(
298 std::log(std::sqrt(threshold_sqr_dist_to_add_new) * 0.5) /
301 int grid_lx = 1 + (cur_gray.
getWidth() >> grid_cell_log2);
302 int grid_ly = 1 + (cur_gray.
getHeight() >> grid_cell_log2);
305 featureList.getOccupiedSectionsMatrix();
309 occupied_sections.
fillAll(
false);
311 for (
size_t i = 0; i < featureList.size(); i++)
314 const int section_idx_x = feat.
pt.x >> grid_cell_log2;
315 const int section_idx_y = feat.
pt.y >> grid_cell_log2;
317 if (!section_idx_x || !section_idx_y || section_idx_x >= grid_lx - 1 ||
318 section_idx_y >= grid_ly - 1)
324 &occupied_sections.
get_unsafe(section_idx_x - 1, section_idx_y - 1);
326 &occupied_sections.
get_unsafe(section_idx_x - 1, section_idx_y);
328 &occupied_sections.
get_unsafe(section_idx_x - 1, section_idx_y + 1);
329 ptr1[0] = ptr1[1] = ptr1[2] =
true;
330 ptr2[0] = ptr2[1] = ptr2[2] =
true;
331 ptr3[0] = ptr3[1] = ptr3[2] =
true;
334 for (
size_t i = 0; i < nNewToCheck && featureList.size() < maxNumFeatures;
338 if (feat.
response < minimum_KLT_response_to_add)
break;
341 const int section_idx_x = feat.
pt.x >> grid_cell_log2;
342 const int section_idx_y = feat.
pt.y >> grid_cell_log2;
344 if (!section_idx_x || !section_idx_y || section_idx_x >= grid_lx - 2 ||
345 section_idx_y >= grid_ly - 2)
349 if (occupied_sections(section_idx_x, section_idx_y))
354 &occupied_sections.
get_unsafe(section_idx_x - 1, section_idx_y - 1);
356 &occupied_sections.
get_unsafe(section_idx_x - 1, section_idx_y);
358 &occupied_sections.
get_unsafe(section_idx_x - 1, section_idx_y + 1);
360 ptr1[0] = ptr1[1] = ptr1[2] =
true;
361 ptr2[0] = ptr2[1] = ptr2[2] =
true;
362 ptr3[0] = ptr3[1] = ptr3[2] =
true;
365 featureList.push_back_fast(feat.
pt.x, feat.
pt.y);
371 newFeat.
ID = ++max_feat_ID_at_input;
382 featureList.getVector());
384 for (
size_t i = 0; i < nNewToCheck && featureList.size() < maxNumFeatures;
388 if (feat.
response < minimum_KLT_response_to_add)
break;
391 double min_dist_sqr = std::numeric_limits<double>::max();
393 if (!featureList.empty())
403 if (min_dist_sqr > threshold_sqr_dist_to_add_new)
406 featureList.push_back_fast(feat.
pt.x, feat.
pt.y);
410 typename FEAT_LIST::feature_t& newFeat = featureList.back();
412 newFeat.ID = ++max_feat_ID_at_input;
427 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
428 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
429 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
432 trackFeatures_addNewFeats_simple_list<TSimpleFeatureList>(
433 featureList, new_feats, sorted_indices, nNewToCheck, maxNumFeatures,
434 minimum_KLT_response_to_add, threshold_sqr_dist_to_add_new, patchSize,
435 cur_gray, max_feat_ID_at_input);
440 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
441 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
442 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
445 trackFeatures_addNewFeats_simple_list<TSimpleFeaturefList>(
446 featureList, new_feats, sorted_indices, nNewToCheck, maxNumFeatures,
447 minimum_KLT_response_to_add, threshold_sqr_dist_to_add_new, patchSize,
448 cur_gray, max_feat_ID_at_input);
452 template <
typename FEATLIST>
454 FEATLIST& trackedFeats,
const size_t img_width,
const size_t img_height,
455 const int MIN_DIST_MARGIN_TO_STOP_TRACKING);
457 template <
typename FEATLIST>
459 FEATLIST& trackedFeats,
const size_t img_width,
const size_t img_height,
460 const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
462 if (trackedFeats.empty())
return 0;
464 std::vector<size_t> survival_idxs;
465 const size_t N = trackedFeats.size();
468 survival_idxs.reserve(N);
469 for (
size_t i = 0; i < N; i++)
471 const typename FEATLIST::feature_t& ft = trackedFeats[i];
477 const int x = ft.pt.x;
478 const int y = ft.pt.y;
479 if (
x < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
480 y < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
481 x >
static_cast<int>(
482 img_width - MIN_DIST_MARGIN_TO_STOP_TRACKING) ||
483 y >
static_cast<int>(
484 img_height - MIN_DIST_MARGIN_TO_STOP_TRACKING))
489 if (!eras) survival_idxs.push_back(i);
493 const size_t N2 = survival_idxs.size();
494 const size_t n_removed = N - N2;
495 for (
size_t i = 0; i < N2; i++)
497 if (survival_idxs[i] != i)
498 trackedFeats[i] = trackedFeats[survival_idxs[i]];
500 trackedFeats.resize(N2);
507 const size_t img_height,
const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
509 return trackFeatures_deleteOOB_impl_simple_feat<TSimpleFeatureList>(
510 trackedFeats, img_width, img_height, MIN_DIST_MARGIN_TO_STOP_TRACKING);
515 const size_t img_height,
const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
517 return trackFeatures_deleteOOB_impl_simple_feat<TSimpleFeaturefList>(
518 trackedFeats, img_width, img_height, MIN_DIST_MARGIN_TO_STOP_TRACKING);
523 CFeatureList& trackedFeats,
const size_t img_width,
const size_t img_height,
524 const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
527 size_t n_removed = 0;
528 while (itFeat != trackedFeats.
end())
535 const float x = (*itFeat)->x;
536 const float y = (*itFeat)->y;
537 if (
x < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
538 y < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
539 x > (img_width - MIN_DIST_MARGIN_TO_STOP_TRACKING) ||
540 y > (img_height - MIN_DIST_MARGIN_TO_STOP_TRACKING))
547 itFeat = trackedFeats.
erase(itFeat);
583 template <
typename FEATLIST>
585 const CImage& old_img,
const CImage& new_img, FEATLIST& featureList)
588 "[CGenericFeatureTracker::trackFeatures] Complete iteration");
590 const size_t img_width = new_img.
getWidth();
591 const size_t img_height = new_img.
getHeight();
596 if (!featureList.empty()) max_feat_ID_at_input = featureList.getMaxID();
600 m_timlog.enter(
"[CGenericFeatureTracker] Convert grayscale");
605 m_timlog.leave(
"[CGenericFeatureTracker] Convert grayscale");
610 m_newly_detected_feats.clear();
612 m_timlog.enter(
"[CGenericFeatureTracker] trackFeatures_impl");
614 trackFeatures_impl(prev_gray, cur_gray, featureList);
616 m_timlog.leave(
"[CGenericFeatureTracker] trackFeatures_impl");
621 const int check_KLT_response_every =
622 extra_params.getWithDefaultVal(
"check_KLT_response_every", 0);
623 const float minimum_KLT_response =
624 extra_params.getWithDefaultVal(
"minimum_KLT_response", 5);
625 const unsigned int KLT_response_half_win =
626 extra_params.getWithDefaultVal(
"KLT_response_half_win", 4);
628 if (check_KLT_response_every > 0 &&
629 ++m_check_KLT_counter >=
size_t(check_KLT_response_every))
631 m_timlog.enter(
"[CGenericFeatureTracker] check KLT responses");
632 m_check_KLT_counter = 0;
634 const unsigned int max_x = img_width - KLT_response_half_win;
635 const unsigned int max_y = img_height - KLT_response_half_win;
638 featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
641 m_timlog.leave(
"[CGenericFeatureTracker] check KLT responses");
649 const bool remove_lost_features =
650 extra_params.getWithDefaultVal(
"remove_lost_features", 0) != 0;
652 if (remove_lost_features)
654 m_timlog.enter(
"[CGenericFeatureTracker] removal of OOB");
656 static const int MIN_DIST_MARGIN_TO_STOP_TRACKING = 10;
659 featureList, img_width, img_height,
660 MIN_DIST_MARGIN_TO_STOP_TRACKING);
662 m_timlog.leave(
"[CGenericFeatureTracker] removal of OOB");
664 last_execution_extra_info.num_deleted_feats = nRemoved;
668 last_execution_extra_info.num_deleted_feats = 0;
674 const int update_patches_every =
675 extra_params.getWithDefaultVal(
"update_patches_every", 0);
677 if (update_patches_every > 0 &&
678 ++m_update_patches_counter >=
size_t(update_patches_every))
680 m_timlog.enter(
"[CGenericFeatureTracker] update patches");
681 m_update_patches_counter = 0;
686 m_timlog.leave(
"[CGenericFeatureTracker] update patches");
692 const bool add_new_features =
693 extra_params.getWithDefaultVal(
"add_new_features", 0) != 0;
694 const double threshold_dist_to_add_new =
695 extra_params.getWithDefaultVal(
"add_new_feat_min_separation", 15);
700 if (add_new_features)
702 m_timlog.enter(
"[CGenericFeatureTracker] add new features");
706 if (m_newly_detected_feats.empty())
710 cur_gray, m_newly_detected_feats, m_detector_adaptive_thres);
713 const size_t N = m_newly_detected_feats.size();
715 last_execution_extra_info.raw_FAST_feats_detected =
719 const size_t desired_num_features = extra_params.getWithDefaultVal(
720 "desired_num_features_adapt",
721 size_t((img_width * img_height) >> 9));
722 updateAdaptiveNewFeatsThreshold(N, desired_num_features);
726 const unsigned int max_x = img_width - KLT_response_half_win;
727 const unsigned int max_y = img_height - KLT_response_half_win;
728 for (
size_t i = 0; i < N; i++)
730 const unsigned int x = m_newly_detected_feats[i].pt.x;
731 const unsigned int y = m_newly_detected_feats[i].pt.y;
732 if (
x > KLT_response_half_win &&
y > KLT_response_half_win &&
733 x < max_x &&
y < max_y)
734 m_newly_detected_feats[i].response =
737 m_newly_detected_feats[i].response = 0;
744 std::vector<size_t> sorted_indices(N);
745 for (
size_t i = 0; i < N; i++) sorted_indices[i] = i;
748 sorted_indices.begin(), sorted_indices.end(),
755 const size_t nNewToCheck =
std::min(
size_t(1500), N);
756 const double threshold_sqr_dist_to_add_new =
757 square(threshold_dist_to_add_new);
758 const size_t maxNumFeatures =
759 extra_params.getWithDefaultVal(
"add_new_feat_max_features", 100);
760 const size_t patchSize =
761 extra_params.getWithDefaultVal(
"add_new_feat_patch_size", 11);
763 const float minimum_KLT_response_to_add =
764 extra_params.getWithDefaultVal(
"minimum_KLT_response_to_add", 10);
768 featureList, m_newly_detected_feats, sorted_indices, nNewToCheck,
769 maxNumFeatures, minimum_KLT_response_to_add,
770 threshold_sqr_dist_to_add_new, patchSize, cur_gray,
771 max_feat_ID_at_input);
773 m_timlog.leave(
"[CGenericFeatureTracker] add new features");
777 "[CGenericFeatureTracker::trackFeatures] Complete iteration");
784 internal_trackFeatures<CFeatureList>(old_img, new_img, featureList);
791 internal_trackFeatures<TSimpleFeatureList>(old_img, new_img, featureList);
798 internal_trackFeatures<TSimpleFeaturefList>(old_img, new_img, featureList);
802 const size_t nNewlyDetectedFeats,
const size_t desired_num_features)
804 const size_t hysteresis_min_num_feats = desired_num_features * 0.9;
805 const size_t hysteresis_max_num_feats = desired_num_features * 1.1;
807 if (nNewlyDetectedFeats < hysteresis_min_num_feats)
808 m_detector_adaptive_thres = std::max(
810 m_detector_adaptive_thres - 1.0,
811 m_detector_adaptive_thres * 0.8));
812 else if (nNewlyDetectedFeats > hysteresis_max_num_feats)
813 m_detector_adaptive_thres = std::max(
814 m_detector_adaptive_thres + 1.0, m_detector_adaptive_thres * 1.2);
832 for (itLeft = leftList.
begin(), itRight = rightList.
begin();
833 itLeft != leftList.
end();)
835 bool delFeat =
false;
836 if ((*itLeft)->x < 0 || (*itLeft)->y < 0 ||
837 (*itRight)->x < 0 || (*itRight)->y < 0 ||
838 fabs((*itLeft)->y - (*itRight)->y) >
843 std::cout <<
"Bad tracked match:";
844 if ((*itLeft)->x < 0 || (*itLeft)->y < 0 || (*itRight)->x < 0 ||
846 std::cout <<
" Out of bounds: (" << (*itLeft)->x <<
","
847 << (*itLeft)->y <<
" & (" << (*itRight)->x <<
","
848 << (*itRight)->y <<
")" << std::endl;
850 if (fabs((*itLeft)->y - (*itRight)->y) > options.
epipolar_TH)
851 std::cout <<
" Bad row checking: "
852 << fabs((*itLeft)->y - (*itRight)->y) << std::endl;
860 (*itLeft)->patch, (*itRight)->patch, u,
v,
res);
864 std::cout <<
"Bad tracked match (correlation failed):"
865 <<
" CC Value: " <<
res << std::endl;
872 itLeft = leftList.
erase(itLeft);
873 itRight = rightList.
erase(itRight);
895 double v_mean, v_std;
896 unsigned int count = 0;
898 dist.setSize(feat_list.size(), 1);
903 for (itPair = feat_list.begin(); itPair != feat_list.end();
912 dist(
count, 0) = sqrt(
913 square(itPair->other_x - itPair->this_x) +
914 square(itPair->other_y - itPair->this_y) +
915 square(itPair->other_z - itPair->this_z));
918 dist.meanAndStdAll(v_mean, v_std);
921 <<
"*****************************************************" << endl;
922 cout <<
"Mean: " << v_mean <<
" - STD: " << v_std << endl;
924 <<
"*****************************************************" << endl;
927 unsigned int idx = 0;
929 for (itPair = feat_list.begin(); itPair != feat_list.end(); idx++)
932 if (fabs(dist(idx, 0) - v_mean) > v_std * numberOfSigmas)
934 cout <<
"Outlier deleted: " << dist(idx, 0) <<
" vs "
935 << v_std * numberOfSigmas << endl;
936 itPair = feat_list.erase(itPair);