13 #include <mrpt/otherlibs/do_opencv_includes.h> 28 template <
typename FEATLIST>
30 FEATLIST& featureList,
const CImage& cur_gray,
31 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
32 const unsigned int max_x,
const unsigned int max_y);
37 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
38 const unsigned int max_x,
const unsigned int max_y)
40 for (
auto& ft : featureList)
45 const unsigned int x = ft.keypoint.pt.x;
46 const unsigned int y = ft.keypoint.pt.y;
47 if (
x > KLT_response_half_win &&
y > KLT_response_half_win &&
48 x < max_x &&
y < max_y)
50 ft.response = cur_gray.KLT_response(
x,
y, KLT_response_half_win);
54 if (ft.response < minimum_KLT_response)
67 template <
class FEAT_LIST>
69 FEAT_LIST& featureList,
const CImage& cur_gray,
70 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
71 const unsigned int max_x_,
const unsigned int max_y_)
73 if (featureList.empty())
return;
75 using pixel_coord_t =
typename FEAT_LIST::feature_t::pixel_coord_t;
76 const auto half_win =
static_cast<pixel_coord_t
>(KLT_response_half_win);
77 const auto max_x =
static_cast<pixel_coord_t
>(max_x_);
78 const auto max_y =
static_cast<pixel_coord_t
>(max_y_);
80 for (
int N = featureList.size() - 1; N >= 0; --N)
82 typename FEAT_LIST::feature_t& ft = featureList[N];
86 if (ft.pt.x > half_win && ft.pt.y > half_win && ft.pt.x < max_x &&
90 cur_gray.
KLT_response(ft.pt.x, ft.pt.y, KLT_response_half_win);
94 if (ft.response < minimum_KLT_response)
110 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
111 const unsigned int max_x,
const unsigned int max_y)
113 trackFeatures_checkResponses_impl_simple<TKeyPointList>(
114 featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
120 const float minimum_KLT_response,
const unsigned int KLT_response_half_win,
121 const unsigned int max_x,
const unsigned int max_y)
123 trackFeatures_checkResponses_impl_simple<TKeyPointfList>(
124 featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
128 template <
typename FEATLIST>
130 FEATLIST& featureList,
const CImage& cur_gray);
136 for (
auto& ft : featureList)
141 const size_t patch_width = ft.patch->getWidth();
142 const size_t patch_height = ft.patch->getHeight();
143 if (patch_width > 0 && patch_height > 0)
147 const int offset = (int)patch_width / 2;
149 cur_gray.extract_patch(
154 catch (std::exception&)
178 template <
typename FEATLIST>
181 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
182 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
183 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
189 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
190 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
191 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
194 const TImageSize imgSize = cur_gray.getSize();
195 const int offset = (int)patchSize / 2 + 1;
196 const int w_off = int(imgSize.
x -
offset);
197 const int h_off = int(imgSize.
y -
offset);
199 for (
size_t i = 0; i < nNewToCheck && featureList.size() < maxNumFeatures;
202 const TKeyPoint& feat = new_feats[sorted_indices[i]];
204 if (feat.
response < minimum_KLT_response_to_add)
continue;
206 double min_dist_sqr =
square(10000);
208 if (!featureList.empty())
211 featureList.kdTreeClosestPoint2DsqrError(feat.
pt.x, feat.
pt.y);
214 if (min_dist_sqr > threshold_sqr_dist_to_add_new &&
233 cur_gray.extract_patch(
238 featureList.emplace_back(std::move(ft));
243 template <
class FEAT_LIST>
246 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
247 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
248 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
255 featureList.getVector());
257 for (
size_t i = 0; i < nNewToCheck && featureList.size() < maxNumFeatures;
260 const TKeyPoint& feat = new_feats[sorted_indices[i]];
261 if (feat.
response < minimum_KLT_response_to_add)
break;
264 double min_dist_sqr = std::numeric_limits<double>::max();
266 if (!featureList.empty())
269 kdtree.kdTreeClosestPoint2DsqrError(feat.
pt.x, feat.
pt.y);
272 if (min_dist_sqr > threshold_sqr_dist_to_add_new)
275 featureList.emplace_back(feat.
pt.x, feat.
pt.y);
276 kdtree.mark_as_outdated();
279 typename FEAT_LIST::feature_t& newFeat = featureList.back();
281 newFeat.ID = ++max_feat_ID_at_input;
294 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
295 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
296 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
299 trackFeatures_addNewFeats_simple_list<TKeyPointList>(
300 featureList, new_feats, sorted_indices, nNewToCheck, maxNumFeatures,
301 minimum_KLT_response_to_add, threshold_sqr_dist_to_add_new, patchSize,
302 cur_gray, max_feat_ID_at_input);
307 const std::vector<size_t>& sorted_indices,
const size_t nNewToCheck,
308 const size_t maxNumFeatures,
const float minimum_KLT_response_to_add,
309 const double threshold_sqr_dist_to_add_new,
const size_t patchSize,
312 trackFeatures_addNewFeats_simple_list<TKeyPointfList>(
313 featureList, new_feats, sorted_indices, nNewToCheck, maxNumFeatures,
314 minimum_KLT_response_to_add, threshold_sqr_dist_to_add_new, patchSize,
315 cur_gray, max_feat_ID_at_input);
319 template <
typename FEATLIST>
321 FEATLIST& trackedFeats,
const size_t img_width,
const size_t img_height,
322 const int MIN_DIST_MARGIN_TO_STOP_TRACKING);
324 template <
typename FEATLIST>
326 FEATLIST& trackedFeats,
const size_t img_width,
const size_t img_height,
327 const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
329 if (trackedFeats.empty())
return 0;
331 std::vector<size_t> survival_idxs;
332 const size_t N = trackedFeats.size();
335 survival_idxs.reserve(N);
336 for (
size_t i = 0; i < N; i++)
338 const typename FEATLIST::feature_t& ft = trackedFeats[i];
344 const int x = ft.pt.x;
345 const int y = ft.pt.y;
346 if (
x < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
347 y < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
348 x > static_cast<int>(
349 img_width - MIN_DIST_MARGIN_TO_STOP_TRACKING) ||
350 y >
static_cast<int>(
351 img_height - MIN_DIST_MARGIN_TO_STOP_TRACKING))
356 if (!eras) survival_idxs.push_back(i);
360 const size_t N2 = survival_idxs.size();
361 const size_t n_removed = N - N2;
362 for (
size_t i = 0; i < N2; i++)
364 if (survival_idxs[i] != i)
365 trackedFeats[i] = trackedFeats[survival_idxs[i]];
367 trackedFeats.resize(N2);
374 const size_t img_height,
const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
376 return trackFeatures_deleteOOB_impl_simple_feat<TKeyPointList>(
377 trackedFeats, img_width, img_height, MIN_DIST_MARGIN_TO_STOP_TRACKING);
382 const size_t img_height,
const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
384 return trackFeatures_deleteOOB_impl_simple_feat<TKeyPointfList>(
385 trackedFeats, img_width, img_height, MIN_DIST_MARGIN_TO_STOP_TRACKING);
390 CFeatureList& trackedFeats,
const size_t img_width,
const size_t img_height,
391 const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
393 auto itFeat = trackedFeats.
begin();
394 size_t n_removed = 0;
395 while (itFeat != trackedFeats.
end())
402 const float x = itFeat->keypoint.pt.x;
403 const float y = itFeat->keypoint.pt.y;
404 if (
x < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
405 y < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
406 x > (img_width - MIN_DIST_MARGIN_TO_STOP_TRACKING) ||
407 y > (img_height - MIN_DIST_MARGIN_TO_STOP_TRACKING))
414 itFeat = trackedFeats.
erase(itFeat);
448 template <
typename FEATLIST>
450 const CImage& old_img,
const CImage& new_img, FEATLIST& featureList)
454 const size_t img_width = new_img.
getWidth();
455 const size_t img_height = new_img.
getHeight();
460 if (!featureList.empty()) max_feat_ID_at_input = featureList.getMaxID();
464 m_timlog.enter(
"CGenericFeatureTracker.to_grayscale");
469 m_timlog.leave(
"CGenericFeatureTracker.to_grayscale");
474 m_newly_detected_feats.clear();
476 m_timlog.enter(
"CGenericFeatureTracker.trackFeatures_impl");
478 trackFeatures_impl(prev_gray, cur_gray, featureList);
480 m_timlog.leave(
"CGenericFeatureTracker.trackFeatures_impl");
485 const int check_KLT_response_every =
486 extra_params.getWithDefaultVal(
"check_KLT_response_every", 1);
487 const float minimum_KLT_response =
488 extra_params.getWithDefaultVal(
"minimum_KLT_response", 30.f);
489 const unsigned int KLT_response_half_win =
490 extra_params.getWithDefaultVal(
"KLT_response_half_win", 8U);
492 if (check_KLT_response_every > 0 &&
493 ++m_check_KLT_counter >=
size_t(check_KLT_response_every))
495 m_timlog.enter(
"CGenericFeatureTracker.check_KLT_responses");
496 m_check_KLT_counter = 0;
498 const unsigned int max_x = img_width - KLT_response_half_win;
499 const unsigned int max_y = img_height - KLT_response_half_win;
502 featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
505 m_timlog.leave(
"CGenericFeatureTracker.check_KLT_responses");
513 const bool remove_lost_features =
514 extra_params.getWithDefaultVal(
"remove_lost_features", 0) != 0;
516 if (remove_lost_features)
518 m_timlog.enter(
"CGenericFeatureTracker.OOB_remove");
520 static const int MIN_DIST_MARGIN_TO_STOP_TRACKING = 10;
523 featureList, img_width, img_height,
524 MIN_DIST_MARGIN_TO_STOP_TRACKING);
526 m_timlog.leave(
"CGenericFeatureTracker.OOB_remove");
528 last_execution_extra_info.num_deleted_feats = nRemoved;
532 last_execution_extra_info.num_deleted_feats = 0;
538 const int update_patches_every =
539 extra_params.getWithDefaultVal(
"update_patches_every", 0);
541 if (update_patches_every > 0 &&
542 ++m_update_patches_counter >=
size_t(update_patches_every))
545 m_timlog,
"CGenericFeatureTracker.update_patches");
547 m_update_patches_counter = 0;
557 const bool add_new_features =
558 extra_params.getWithDefaultVal(
"add_new_features", 1) != 0;
559 const double threshold_dist_to_add_new =
560 extra_params.getWithDefaultVal(
"add_new_feat_min_separation", 15);
564 if (add_new_features)
567 m_timlog,
"CGenericFeatureTracker.add_new_features");
571 if (m_newly_detected_feats.empty())
574 const int fast_v = extra_params.getWithDefaultVal(
575 "add_new_features_FAST_version", 10);
581 cur_gray, m_newly_detected_feats,
582 m_detector_adaptive_thres);
586 cur_gray, m_newly_detected_feats,
587 m_detector_adaptive_thres);
591 cur_gray, m_newly_detected_feats,
592 m_detector_adaptive_thres);
596 "Invalid value for `add_new_features_FAST_version`: " 597 "valid are 9,10,12");
602 const size_t N = m_newly_detected_feats.size();
603 last_execution_extra_info.raw_FAST_feats_detected = N;
606 const size_t desired_num_features = extra_params.getWithDefaultVal(
607 "desired_num_features_adapt",
608 size_t((img_width * img_height) >> 9));
609 updateAdaptiveNewFeatsThreshold(N, desired_num_features);
613 const unsigned int max_x = img_width - KLT_response_half_win;
614 const unsigned int max_y = img_height - KLT_response_half_win;
615 for (
size_t i = 0; i < N; i++)
617 const unsigned int x = m_newly_detected_feats[i].pt.x;
618 const unsigned int y = m_newly_detected_feats[i].pt.y;
619 if (
x > KLT_response_half_win &&
y > KLT_response_half_win &&
620 x < max_x &&
y < max_y)
621 m_newly_detected_feats[i].response =
624 m_newly_detected_feats[i].response = 0;
631 std::vector<size_t> sorted_indices(N);
632 for (
size_t i = 0; i < N; i++) sorted_indices[i] = i;
635 sorted_indices.begin(), sorted_indices.end(),
642 const size_t nNewToCheck =
std::min(
size_t(1500), N);
643 const double threshold_sqr_dist_to_add_new =
644 square(threshold_dist_to_add_new);
645 const size_t maxNumFeatures =
646 extra_params.getWithDefaultVal(
"add_new_feat_max_features", 100U);
647 const size_t patchSize =
648 extra_params.getWithDefaultVal(
"add_new_feat_patch_size", 0U);
649 const float minimum_KLT_response_to_add =
650 extra_params.getWithDefaultVal(
"minimum_KLT_response_to_add", 70.f);
654 featureList, m_newly_detected_feats, sorted_indices, nNewToCheck,
655 maxNumFeatures, minimum_KLT_response_to_add,
656 threshold_sqr_dist_to_add_new, patchSize, cur_gray,
657 max_feat_ID_at_input);
665 internal_trackFeatures<TKeyPointList>(old_img, new_img, featureList);
671 internal_trackFeatures<TKeyPointfList>(old_img, new_img, featureList);
675 const size_t nNewlyDetectedFeats,
const size_t desired_num_features)
677 const size_t hysteresis_min_num_feats = desired_num_features * 0.9;
678 const size_t hysteresis_max_num_feats = desired_num_features * 1.1;
680 if (nNewlyDetectedFeats < hysteresis_min_num_feats)
681 m_detector_adaptive_thres = std::max(
683 m_detector_adaptive_thres - 1.0,
684 m_detector_adaptive_thres * 0.8));
685 else if (nNewlyDetectedFeats > hysteresis_max_num_feats)
686 m_detector_adaptive_thres = std::max(
687 m_detector_adaptive_thres + 1.0, m_detector_adaptive_thres * 1.2);
void trackFeatures_addNewFeats< CFeatureList >(CFeatureList &featureList, const TKeyPointList &new_feats, const std::vector< size_t > &sorted_indices, const size_t nNewToCheck, const size_t maxNumFeatures, const float minimum_KLT_response_to_add, const double threshold_sqr_dist_to_add_new, const size_t patchSize, const CImage &cur_gray, TFeatureID &max_feat_ID_at_input)
Helper class: KD-tree search class for vector<KeyPoint>: Call mark_as_outdated() to force rebuilding ...
uint64_t TFeatureID
Definition of a feature ID.
void trackFeatures(const mrpt::img::CImage &old_img, const mrpt::img::CImage &new_img, TKeyPointList &inout_featureList)
Perform feature tracking from "old_img" to "new_img", with a (possibly empty) list of previously trac...
#define THROW_EXCEPTION(msg)
A safe way to call enter() and leave() of a mrpt::system::CTimeLogger upon construction and destructi...
size_t trackFeatures_deleteOOB_impl_simple_feat(FEATLIST &trackedFeats, const size_t img_width, const size_t img_height, const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
TKeyPointMethod type
Keypoint method used to detect this feature.
void internal_trackFeatures(const mrpt::img::CImage &old_img, const mrpt::img::CImage &new_img, FEATLIST &inout_featureList)
Perform feature tracking from "old_img" to "new_img", with a (possibly empty) list of previously trac...
Unable to track this feature (mismatch is too high for the given tracking window: lack of texture...
size_t getHeight() const override
Returns the height of the image in pixels.
This file implements miscelaneous matrix and matrix/vector operations, and internal functions in mrpt...
void trackFeatures_checkResponses< TKeyPointfList >(TKeyPointfList &featureList, const CImage &cur_gray, const float minimum_KLT_response, const unsigned int KLT_response_half_win, const unsigned int max_x, const unsigned int max_y)
TFeatureID ID
ID of the feature.
Simple structure for image key points.
void trackFeatures_updatePatch< TKeyPointfList >(TKeyPointfList &featureList, const CImage &cur_gray)
void trackFeatures_checkResponses_impl_simple(FEAT_LIST &featureList, const CImage &cur_gray, const float minimum_KLT_response, const unsigned int KLT_response_half_win, const unsigned int max_x_, const unsigned int max_y_)
static void detectFeatures_SSE2_FASTER10(const mrpt::img::CImage &img, TKeyPointList &corners, const int threshold=20, bool append_to_list=false, uint8_t octave=0, std::vector< size_t > *out_feats_index_by_row=nullptr)
Just like detectFeatures_SSE2_FASTER9() for another version of the detector.
A helper struct to sort keypoints by their response: It can be used with these types: ...
T square(const T x)
Inline function for the square of a number.
virtual void trackFeatures_impl(const mrpt::img::CImage &old_img, const mrpt::img::CImage &new_img, TKeyPointfList &inout_featureList)
The tracking method implementation, to be implemented in children classes.
Inactive (right after detection, and before being tried to track)
This base provides a set of functions for maths stuff.
size_t getWidth() const override
Returns the width of the image in pixels.
float KLT_response(const unsigned int x, const unsigned int y, const unsigned int half_window_size) const
Compute the KLT response at a given pixel (x,y) - Only for grayscale images (for efficiency it avoids...
std::optional< mrpt::img::CImage > patch
A patch of the image surrounding the feature.
Feature fell Out Of Bounds (out of the image limits, too close to image borders)
void updateAdaptiveNewFeatsThreshold(const size_t nNewlyDetectedFeats, const size_t desired_num_features)
Adapts the threshold m_detector_adaptive_thres according to the real and desired number of features j...
A pair (x,y) of pixel coordinates (integer resolution).
Classes for computer vision, detectors, features, etc.
A generic 2D feature from an image, extracted with CFeatureExtraction Each feature may have one or mo...
iterator erase(const iterator &it)
FAST feature detector, OpenCV's implementation ("Faster and better: A machine learning approach to...
A list of visual features, to be used as output by detectors, as input/output by trackers, etc.
void trackFeatures_addNewFeats< TKeyPointList >(TKeyPointList &featureList, const TKeyPointList &new_feats, const std::vector< size_t > &sorted_indices, const size_t nNewToCheck, const size_t maxNumFeatures, const float minimum_KLT_response_to_add, const double threshold_sqr_dist_to_add_new, const size_t patchSize, const CImage &cur_gray, TFeatureID &max_feat_ID_at_input)
float response
A measure of the "goodness" of the feature.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void trackFeatures_checkResponses(FEATLIST &featureList, const CImage &cur_gray, const float minimum_KLT_response, const unsigned int KLT_response_half_win, const unsigned int max_x, const unsigned int max_y)
size_t trackFeatures_deleteOOB(FEATLIST &trackedFeats, const size_t img_width, const size_t img_height, const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
uint8_t octave
The image octave the image was found in: 0=original image, 1=1/2 image, 2=1/4 image, etc.
void trackFeatures_updatePatch< CFeatureList >(CFeatureList &featureList, const CImage &cur_gray)
void trackFeatures_addNewFeats(FEATLIST &featureList, const TKeyPointList &new_feats, const std::vector< size_t > &sorted_indices, const size_t nNewToCheck, const size_t maxNumFeatures, const float minimum_KLT_response_to_add, const double threshold_sqr_dist_to_add_new, const size_t patchSize, const CImage &cur_gray, TFeatureID &max_feat_ID_at_input)
static void detectFeatures_SSE2_FASTER9(const mrpt::img::CImage &img, TKeyPointList &corners, const int threshold=20, bool append_to_list=false, uint8_t octave=0, std::vector< size_t > *out_feats_index_by_row=nullptr)
A SSE2-optimized implementation of FASTER-9 (requires img to be grayscale).
void trackFeatures_addNewFeats_simple_list(FEAT_LIST &featureList, const TKeyPointList &new_feats, const std::vector< size_t > &sorted_indices, const size_t nNewToCheck, const size_t maxNumFeatures, const float minimum_KLT_response_to_add, const double threshold_sqr_dist_to_add_new, const size_t patchSize, const CImage &cur_gray, TFeatureID &max_feat_ID_at_input)
Feature correctly tracked.
void trackFeatures_checkResponses< CFeatureList >(CFeatureList &featureList, const CImage &cur_gray, const float minimum_KLT_response, const unsigned int KLT_response_half_win, const unsigned int max_x, const unsigned int max_y)
float orientation
Main orientation of the feature.
static void detectFeatures_SSE2_FASTER12(const mrpt::img::CImage &img, TKeyPointList &corners, const int threshold=20, bool append_to_list=false, uint8_t octave=0, std::vector< size_t > *out_feats_index_by_row=nullptr)
Just like detectFeatures_SSE2_FASTER9() for another version of the detector.
Functions for estimating the optimal transformation between two frames of references given measuremen...
float response
A measure of the "goodness" of the feature (typically, the KLT_response value)
uint16_t patchSize
Size of the patch (patchSize x patchSize) (it must be an odd number)
void trackFeatures_updatePatch(FEATLIST &featureList, const CImage &cur_gray)
size_t trackFeatures_deleteOOB(CFeatureList &trackedFeats, const size_t img_width, const size_t img_height, const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
void trackFeatures_addNewFeats< TKeyPointfList >(TKeyPointfList &featureList, const TKeyPointList &new_feats, const std::vector< size_t > &sorted_indices, const size_t nNewToCheck, const size_t maxNumFeatures, const float minimum_KLT_response_to_add, const double threshold_sqr_dist_to_add_new, const size_t patchSize, const CImage &cur_gray, TFeatureID &max_feat_ID_at_input)
pixel_coords_t pt
Coordinates in the image.
void trackFeatures_checkResponses< TKeyPointList >(TKeyPointList &featureList, const CImage &cur_gray, const float minimum_KLT_response, const unsigned int KLT_response_half_win, const unsigned int max_x, const unsigned int max_y)
void trackFeatures_updatePatch< TKeyPointList >(TKeyPointList &featureList, const CImage &cur_gray)
A class for storing images as grayscale or RGB bitmaps.
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
int round(const T value)
Returns the closer integer (int) to x.