Main MRPT website > C++ reference for MRPT 1.9.9
tracking.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "vision-precomp.h" // Precompiled headers
11 
12 #include <mrpt/vision/tracking.h>
13 
15 
16 // Universal include for all versions of OpenCV
17 #include <mrpt/otherlibs/do_opencv_includes.h>
18 
19 using namespace mrpt;
20 using namespace mrpt::vision;
21 using namespace mrpt::utils;
22 using namespace mrpt::math;
23 using namespace std;
24 
25 // ------------------------------- internal helper templates
26 // ---------------------------------
27 namespace mrpt
28 {
29 namespace vision
30 {
31 namespace detail
32 {
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);
38 
39 template <>
41  CFeatureList& featureList, const CImage& cur_gray,
42  const float minimum_KLT_response, const unsigned int KLT_response_half_win,
43  const unsigned int max_x, const unsigned int max_y)
44 {
45  const CFeatureList::iterator itFeatEnd = featureList.end();
46  for (CFeatureList::iterator itFeat = featureList.begin();
47  itFeat != itFeatEnd; ++itFeat)
48  {
49  CFeature* ft = itFeat->get();
50  if (ft->track_status != status_TRACKED)
51  continue; // Skip if it's not correctly tracked.
52 
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)
57  { // Update response:
58  ft->response = cur_gray.KLT_response(x, y, KLT_response_half_win);
59 
60  // Is it good enough?
61  // http://grooveshark.com/s/Goonies+Are+Good+Enough/2beBfO?src=5
62  if (ft->response < minimum_KLT_response)
63  { // Nope!
65  }
66  }
67  else
68  { // Out of bounds
69  ft->response = 0;
71  }
72  }
73 } // end of trackFeatures_checkResponses<>
74 
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_)
80 {
81  if (featureList.empty()) return;
82 
83  typedef typename FEAT_LIST::feature_t::pixel_coord_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_);
88 
89  for (int N = featureList.size() - 1; N >= 0; --N)
90  {
91  typename FEAT_LIST::feature_t& ft = featureList[N];
92  if (ft.track_status != status_TRACKED)
93  continue; // Skip if it's not correctly tracked.
94 
95  if (ft.pt.x > half_win && ft.pt.y > half_win && ft.pt.x < max_x &&
96  ft.pt.y < max_y)
97  { // Update response:
98  ft.response =
99  cur_gray.KLT_response(ft.pt.x, ft.pt.y, KLT_response_half_win);
100 
101  // Is it good enough?
102  // http://grooveshark.com/s/Goonies+Are+Good+Enough/2beBfO?src=5
103  if (ft.response < minimum_KLT_response)
104  { // Nope!
105  ft.track_status = status_LOST;
106  }
107  }
108  else
109  { // Out of bounds
110  ft.response = 0;
111  ft.track_status = status_OOB;
112  }
113  }
114 } // end of trackFeatures_checkResponses<>
115 
116 template <>
118  TSimpleFeatureList& featureList, const CImage& cur_gray,
119  const float minimum_KLT_response, const unsigned int KLT_response_half_win,
120  const unsigned int max_x, const unsigned int max_y)
121 {
122  trackFeatures_checkResponses_impl_simple<TSimpleFeatureList>(
123  featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
124  max_x, max_y);
125 }
126 template <>
128  TSimpleFeaturefList& featureList, const CImage& cur_gray,
129  const float minimum_KLT_response, const unsigned int KLT_response_half_win,
130  const unsigned int max_x, const unsigned int max_y)
131 {
132  trackFeatures_checkResponses_impl_simple<TSimpleFeaturefList>(
133  featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
134  max_x, max_y);
135 }
136 
137 template <typename FEATLIST>
138 inline void trackFeatures_updatePatch(
139  FEATLIST& featureList, const CImage& cur_gray);
140 
141 template <>
143  CFeatureList& featureList, const CImage& cur_gray)
144 {
145  for (CFeatureList::iterator itFeat = featureList.begin();
146  itFeat != featureList.end(); ++itFeat)
147  {
148  CFeature* ft = itFeat->get();
149  if (ft->track_status != status_TRACKED)
150  continue; // Skip if it's not correctly tracked.
151 
152  const size_t patch_width = ft->patch.getWidth();
153  const size_t patch_height = ft->patch.getHeight();
154  if (patch_width > 0 && patch_height > 0)
155  {
156  try
157  {
158  const int offset = (int)patch_width / 2; // + 1;
159  cur_gray.extract_patch(
160  ft->patch, round(ft->x) - offset, round(ft->y) - offset,
161  patch_width, patch_height);
162  }
163  catch (std::exception&)
164  {
165  ft->track_status = status_OOB; // Out of bounds!
166  }
167  }
168  }
169 } // end of trackFeatures_updatePatch<>
170 template <>
172  TSimpleFeatureList& featureList, const CImage& cur_gray)
173 {
174  MRPT_UNUSED_PARAM(featureList);
175  MRPT_UNUSED_PARAM(cur_gray);
176  // This list type does not have patch stored explicitly
177 } // end of trackFeatures_updatePatch<>
178 template <>
180  TSimpleFeaturefList& featureList, const CImage& cur_gray)
181 {
182  MRPT_UNUSED_PARAM(featureList);
183  MRPT_UNUSED_PARAM(cur_gray);
184  // This list type does not have patch stored explicitly
185 } // end of trackFeatures_updatePatch<>
186 
187 template <typename FEATLIST>
188 inline void trackFeatures_addNewFeats(
189  FEATLIST& featureList, const TSimpleFeatureList& new_feats,
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,
193  const CImage& cur_gray, TFeatureID& max_feat_ID_at_input);
194 
195 template <>
197  CFeatureList& featureList, const TSimpleFeatureList& new_feats,
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,
201  const CImage& cur_gray, TFeatureID& max_feat_ID_at_input)
202 {
203  const TImageSize imgSize = cur_gray.getSize();
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);
207 
208  for (size_t i = 0; i < nNewToCheck && featureList.size() < maxNumFeatures;
209  i++)
210  {
211  const TSimpleFeature& feat = new_feats[sorted_indices[i]];
212 
213  if (feat.response < minimum_KLT_response_to_add) continue;
214 
215  double min_dist_sqr = square(10000);
216 
217  if (!featureList.empty())
218  {
219  // m_timlog.enter("[CGenericFeatureTracker] add new
220  // features.kdtree");
221  min_dist_sqr =
222  featureList.kdTreeClosestPoint2DsqrError(feat.pt.x, feat.pt.y);
223  // m_timlog.leave("[CGenericFeatureTracker] add new
224  // features.kdtree");
225  }
226 
227  if (min_dist_sqr > threshold_sqr_dist_to_add_new &&
228  feat.pt.x > offset && feat.pt.y > offset && feat.pt.x < w_off &&
229  feat.pt.y < h_off)
230  {
231  // Add new feature:
232  CFeature::Ptr ft = mrpt::make_aligned_shared<CFeature>();
233  ft->type = featFAST;
234  ft->ID = ++max_feat_ID_at_input;
235  ft->x = feat.pt.x;
236  ft->y = feat.pt.y;
237  ft->response = feat.response;
238  ft->orientation = 0;
239  ft->scale = 1;
240  ft->patchSize = patchSize; // The size of the feature patch
241 
242  if (patchSize > 0)
243  cur_gray.extract_patch(
244  ft->patch, round(ft->x) - offset, round(ft->y) - offset,
245  patchSize,
246  patchSize); // Image patch surronding the feature
247 
248  featureList.push_back(ft);
249  }
250  }
251 } // end of trackFeatures_addNewFeats<>
252 
253 template <class FEAT_LIST>
255  FEAT_LIST& featureList, const TSimpleFeatureList& new_feats,
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,
259  const CImage& cur_gray, TFeatureID& max_feat_ID_at_input)
260 {
261 #if 0
262  // Brute-force version:
263  const int max_manhatan_dist = std::sqrt(2*threshold_sqr_dist_to_add_new);
264 
265  for (size_t i=0;i<nNewToCheck && featureList.size()<maxNumFeatures;i++)
266  {
267  const TSimpleFeature &feat = new_feats[ sorted_indices[i] ];
268  if (feat.response<minimum_KLT_response_to_add) break; // continue;
269 
270  // Check the min-distance:
271  int manh_dist = std::numeric_limits<int>::max();
272  for (size_t j=0;j<featureList.size();j++)
273  {
274  const TSimpleFeature &existing = featureList[j];
275  const int d = std::abs(existing.pt.x-feat.pt.x)+std::abs(existing.pt.y-feat.pt.y);
276  mrpt::utils::keep_min(manh_dist, d);
277  }
278 
279  if (manh_dist<max_manhatan_dist)
280  continue; // Already occupied! skip.
281 
282  // OK: accept it
283  featureList.push_back_fast(feat.pt.x,feat.pt.y); // (x,y)
284  //featureList.mark_kdtree_as_outdated();
285 
286  // Fill out the rest of data:
287  TSimpleFeature &newFeat = featureList.back();
288 
289  newFeat.ID = ++max_feat_ID_at_input;
290  newFeat.response = feat.response;
291  newFeat.octave = 0;
292  /** Inactive: right after detection, and before being tried to track */
293  newFeat.track_status = status_IDLE;
294  }
295 #elif 0
296  // Version with an occupancy grid:
297  const int grid_cell_log2 = round(
298  std::log(std::sqrt(threshold_sqr_dist_to_add_new) * 0.5) /
299  std::log(2.0));
300 
301  int grid_lx = 1 + (cur_gray.getWidth() >> grid_cell_log2);
302  int grid_ly = 1 + (cur_gray.getHeight() >> grid_cell_log2);
303 
304  mrpt::math::CMatrixBool& occupied_sections =
305  featureList.getOccupiedSectionsMatrix();
306 
307  occupied_sections.setSize(
308  grid_lx, grid_ly); // See the comments above for an explanation.
309  occupied_sections.fillAll(false);
310 
311  for (size_t i = 0; i < featureList.size(); i++)
312  {
313  const TSimpleFeature& feat = featureList[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;
316 
317  if (!section_idx_x || !section_idx_y || section_idx_x >= grid_lx - 1 ||
318  section_idx_y >= grid_ly - 1)
319  continue; // This may be too radical, but speeds up the logic
320  // below...
321 
322  // Mark sections as occupied
323  bool* ptr1 =
324  &occupied_sections.get_unsafe(section_idx_x - 1, section_idx_y - 1);
325  bool* ptr2 =
326  &occupied_sections.get_unsafe(section_idx_x - 1, section_idx_y);
327  bool* ptr3 =
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;
332  }
333 
334  for (size_t i = 0; i < nNewToCheck && featureList.size() < maxNumFeatures;
335  i++)
336  {
337  const TSimpleFeature& feat = new_feats[sorted_indices[i]];
338  if (feat.response < minimum_KLT_response_to_add) break; // continue;
339 
340  // Check the min-distance:
341  const int section_idx_x = feat.pt.x >> grid_cell_log2;
342  const int section_idx_y = feat.pt.y >> grid_cell_log2;
343 
344  if (!section_idx_x || !section_idx_y || section_idx_x >= grid_lx - 2 ||
345  section_idx_y >= grid_ly - 2)
346  continue; // This may be too radical, but speeds up the logic
347  // below...
348 
349  if (occupied_sections(section_idx_x, section_idx_y))
350  continue; // Already occupied! skip.
351 
352  // Mark section as occupied
353  bool* ptr1 =
354  &occupied_sections.get_unsafe(section_idx_x - 1, section_idx_y - 1);
355  bool* ptr2 =
356  &occupied_sections.get_unsafe(section_idx_x - 1, section_idx_y);
357  bool* ptr3 =
358  &occupied_sections.get_unsafe(section_idx_x - 1, section_idx_y + 1);
359 
360  ptr1[0] = ptr1[1] = ptr1[2] = true;
361  ptr2[0] = ptr2[1] = ptr2[2] = true;
362  ptr3[0] = ptr3[1] = ptr3[2] = true;
363 
364  // OK: accept it
365  featureList.push_back_fast(feat.pt.x, feat.pt.y); // (x,y)
366  // featureList.mark_kdtree_as_outdated();
367 
368  // Fill out the rest of data:
369  TSimpleFeature& newFeat = featureList.back();
370 
371  newFeat.ID = ++max_feat_ID_at_input;
372  newFeat.response = feat.response;
373  newFeat.octave = 0;
374  /** Inactive: right after detection, and before being tried to track */
375  newFeat.track_status = status_IDLE;
376  }
377 #else
378  MRPT_UNUSED_PARAM(patchSize);
379  MRPT_UNUSED_PARAM(cur_gray);
380  // Version with KD-tree
382  featureList.getVector());
383 
384  for (size_t i = 0; i < nNewToCheck && featureList.size() < maxNumFeatures;
385  i++)
386  {
387  const TSimpleFeature& feat = new_feats[sorted_indices[i]];
388  if (feat.response < minimum_KLT_response_to_add) break; // continue;
389 
390  // Check the min-distance:
391  double min_dist_sqr = std::numeric_limits<double>::max();
392 
393  if (!featureList.empty())
394  {
395  // m_timlog.enter("[CGenericFeatureTracker] add new
396  // features.kdtree");
397  min_dist_sqr =
398  kdtree.kdTreeClosestPoint2DsqrError(feat.pt.x, feat.pt.y);
399  // m_timlog.leave("[CGenericFeatureTracker] add new
400  // features.kdtree");
401  }
402 
403  if (min_dist_sqr > threshold_sqr_dist_to_add_new)
404  {
405  // OK: accept it
406  featureList.push_back_fast(feat.pt.x, feat.pt.y); // (x,y)
407  kdtree.mark_as_outdated();
408 
409  // Fill out the rest of data:
410  typename FEAT_LIST::feature_t& newFeat = featureList.back();
411 
412  newFeat.ID = ++max_feat_ID_at_input;
413  newFeat.response = feat.response;
414  newFeat.octave = 0;
415  /** Inactive: right after detection, and before being tried to track
416  */
417  newFeat.track_status = status_IDLE;
418  }
419  }
420 
421 #endif
422 } // end of trackFeatures_addNewFeats<>
423 
424 template <>
426  TSimpleFeatureList& featureList, const TSimpleFeatureList& new_feats,
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,
430  const CImage& cur_gray, TFeatureID& max_feat_ID_at_input)
431 {
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);
436 }
437 template <>
439  TSimpleFeaturefList& featureList, const TSimpleFeatureList& new_feats,
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,
443  const CImage& cur_gray, TFeatureID& max_feat_ID_at_input)
444 {
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);
449 }
450 
451 // Return the number of removed features
452 template <typename FEATLIST>
453 inline size_t trackFeatures_deleteOOB(
454  FEATLIST& trackedFeats, const size_t img_width, const size_t img_height,
455  const int MIN_DIST_MARGIN_TO_STOP_TRACKING);
456 
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)
461 {
462  if (trackedFeats.empty()) return 0;
463 
464  std::vector<size_t> survival_idxs;
465  const size_t N = trackedFeats.size();
466 
467  // 1st: Build list of survival indexes:
468  survival_idxs.reserve(N);
469  for (size_t i = 0; i < N; i++)
470  {
471  const typename FEATLIST::feature_t& ft = trackedFeats[i];
472  const TFeatureTrackStatus status = ft.track_status;
473  bool eras = (status_TRACKED != status && status_IDLE != status);
474  if (!eras)
475  {
476  // Also, check if it's too close to the image border:
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))
485  {
486  eras = true;
487  }
488  }
489  if (!eras) survival_idxs.push_back(i);
490  }
491 
492  // 2nd: Build updated list:
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++)
496  {
497  if (survival_idxs[i] != i)
498  trackedFeats[i] = trackedFeats[survival_idxs[i]];
499  }
500  trackedFeats.resize(N2);
501  return n_removed;
502 } // end of trackFeatures_deleteOOB
503 
504 template <>
506  TSimpleFeatureList& trackedFeats, const size_t img_width,
507  const size_t img_height, const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
508 {
509  return trackFeatures_deleteOOB_impl_simple_feat<TSimpleFeatureList>(
510  trackedFeats, img_width, img_height, MIN_DIST_MARGIN_TO_STOP_TRACKING);
511 }
512 template <>
514  TSimpleFeaturefList& trackedFeats, const size_t img_width,
515  const size_t img_height, const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
516 {
517  return trackFeatures_deleteOOB_impl_simple_feat<TSimpleFeaturefList>(
518  trackedFeats, img_width, img_height, MIN_DIST_MARGIN_TO_STOP_TRACKING);
519 }
520 
521 template <>
523  CFeatureList& trackedFeats, const size_t img_width, const size_t img_height,
524  const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
525 {
526  MRPT_UNUSED_PARAM(MIN_DIST_MARGIN_TO_STOP_TRACKING);
527  CFeatureList::iterator itFeat = trackedFeats.begin();
528  size_t n_removed = 0;
529  while (itFeat != trackedFeats.end())
530  {
531  const TFeatureTrackStatus status = (*itFeat)->track_status;
532  bool eras = (status_TRACKED != status && status_IDLE != status);
533  if (!eras)
534  {
535  // Also, check if it's too close to the image border:
536  const float x = (*itFeat)->x;
537  const float y = (*itFeat)->y;
538  static const float MIN_DIST_MARGIN_TO_STOP_TRACKING = 10;
539  if (x < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
540  y < MIN_DIST_MARGIN_TO_STOP_TRACKING ||
541  x > (img_width - MIN_DIST_MARGIN_TO_STOP_TRACKING) ||
542  y > (img_height - MIN_DIST_MARGIN_TO_STOP_TRACKING))
543  {
544  eras = true;
545  }
546  }
547  if (eras) // Erase or keep?
548  {
549  itFeat = trackedFeats.erase(itFeat);
550  n_removed++;
551  }
552  else
553  ++itFeat;
554  }
555  return n_removed;
556 } // end of trackFeatures_deleteOOB
557 }
558 }
559 } // end NS's
560 // ---------------------------- end of internal helper templates
561 // -------------------------------
562 
564  const CImage& old_img, const CImage& new_img,
565  TSimpleFeaturefList& inout_featureList)
566 {
567  MRPT_UNUSED_PARAM(old_img);
568  MRPT_UNUSED_PARAM(new_img);
569  MRPT_UNUSED_PARAM(inout_featureList);
570  THROW_EXCEPTION("Method not implemented by derived class!")
571 }
572 
573 /** Perform feature tracking from "old_img" to "new_img", with a (possibly
574  *empty) list of previously tracked features "featureList".
575  * This is a list of parameters (in "extraParams") accepted by ALL
576  *implementations of feature tracker (see each derived class for more specific
577  *parameters).
578  * - "add_new_features" (Default=0). If set to "1", new features will be
579  *also
580  *added to the existing ones in areas of the image poor of features.
581  * This method actually first call the pure virtual "trackFeatures_impl"
582  *method, then implements the optional detection of new features if
583  *"add_new_features"!=0.
584  */
585 template <typename FEATLIST>
587  const CImage& old_img, const CImage& new_img, FEATLIST& featureList)
588 {
589  m_timlog.enter(
590  "[CGenericFeatureTracker::trackFeatures] Complete iteration");
591 
592  const size_t img_width = new_img.getWidth();
593  const size_t img_height = new_img.getHeight();
594 
595  // Take the maximum ID of "old" features so new feats (if
596  // "add_new_features==true") will be id+1, id+2, ...
597  TFeatureID max_feat_ID_at_input = 0;
598  if (!featureList.empty()) max_feat_ID_at_input = featureList.getMaxID();
599 
600  // Grayscale images
601  // =========================================
602  m_timlog.enter("[CGenericFeatureTracker] Convert grayscale");
603 
604  const CImage prev_gray(old_img, FAST_REF_OR_CONVERT_TO_GRAY);
605  const CImage cur_gray(new_img, FAST_REF_OR_CONVERT_TO_GRAY);
606 
607  m_timlog.leave("[CGenericFeatureTracker] Convert grayscale");
608 
609  // =================================
610  // (1st STEP) Do the actual tracking
611  // =================================
612  m_newly_detected_feats.clear();
613 
614  m_timlog.enter("[CGenericFeatureTracker] trackFeatures_impl");
615 
616  trackFeatures_impl(prev_gray, cur_gray, featureList);
617 
618  m_timlog.leave("[CGenericFeatureTracker] trackFeatures_impl");
619 
620  // ========================================================
621  // (2nd STEP) For successfully followed features, check their KLT response??
622  // ========================================================
623  const int check_KLT_response_every =
624  extra_params.getWithDefaultVal("check_KLT_response_every", 0);
625  const float minimum_KLT_response =
626  extra_params.getWithDefaultVal("minimum_KLT_response", 5);
627  const unsigned int KLT_response_half_win =
628  extra_params.getWithDefaultVal("KLT_response_half_win", 4);
629 
630  if (check_KLT_response_every > 0 &&
631  ++m_check_KLT_counter >= size_t(check_KLT_response_every))
632  {
633  m_timlog.enter("[CGenericFeatureTracker] check KLT responses");
634  m_check_KLT_counter = 0;
635 
636  const unsigned int max_x = img_width - KLT_response_half_win;
637  const unsigned int max_y = img_height - KLT_response_half_win;
638 
640  featureList, cur_gray, minimum_KLT_response, KLT_response_half_win,
641  max_x, max_y);
642 
643  m_timlog.leave("[CGenericFeatureTracker] check KLT responses");
644 
645  } // end check_KLT_response_every
646 
647  // ============================================================
648  // (3rd STEP) Remove Out-of-bounds or badly tracked features
649  // or those marked as "bad" by their low KLT response
650  // ============================================================
651  const bool remove_lost_features =
652  extra_params.getWithDefaultVal("remove_lost_features", 0) != 0;
653 
654  if (remove_lost_features)
655  {
656  m_timlog.enter("[CGenericFeatureTracker] removal of OOB");
657 
658  static const int MIN_DIST_MARGIN_TO_STOP_TRACKING = 10;
659 
660  const size_t nRemoved = detail::trackFeatures_deleteOOB(
661  featureList, img_width, img_height,
662  MIN_DIST_MARGIN_TO_STOP_TRACKING);
663 
664  m_timlog.leave("[CGenericFeatureTracker] removal of OOB");
665 
666  last_execution_extra_info.num_deleted_feats = nRemoved;
667  }
668  else
669  {
670  last_execution_extra_info.num_deleted_feats = 0;
671  }
672 
673  // ========================================================
674  // (4th STEP) For successfully followed features, update its patch:
675  // ========================================================
676  const int update_patches_every =
677  extra_params.getWithDefaultVal("update_patches_every", 0);
678 
679  if (update_patches_every > 0 &&
680  ++m_update_patches_counter >= size_t(update_patches_every))
681  {
682  m_timlog.enter("[CGenericFeatureTracker] update patches");
683  m_update_patches_counter = 0;
684 
685  // Update the patch for each valid feature:
686  detail::trackFeatures_updatePatch(featureList, cur_gray);
687 
688  m_timlog.leave("[CGenericFeatureTracker] update patches");
689  } // end if update_patches_every
690 
691  // ========================================================
692  // (5th STEP) Do detection of new features??
693  // ========================================================
694  const bool add_new_features =
695  extra_params.getWithDefaultVal("add_new_features", 0) != 0;
696  const double threshold_dist_to_add_new =
697  extra_params.getWithDefaultVal("add_new_feat_min_separation", 15);
698 
699  // Additional operation: if "add_new_features==true", find new features and
700  // add them in
701  // areas spare of valid features:
702  if (add_new_features)
703  {
704  m_timlog.enter("[CGenericFeatureTracker] add new features");
705 
706  // Look for new features and save in "m_newly_detected_feats", if
707  // they're not already computed:
708  if (m_newly_detected_feats.empty())
709  {
710  // Do the detection
712  cur_gray, m_newly_detected_feats, m_detector_adaptive_thres);
713  }
714 
715  const size_t N = m_newly_detected_feats.size();
716 
717  last_execution_extra_info.raw_FAST_feats_detected =
718  N; // Extra out info.
719 
720  // Update the adaptive threshold.
721  const size_t desired_num_features = extra_params.getWithDefaultVal(
722  "desired_num_features_adapt",
723  size_t((img_width * img_height) >> 9));
724  updateAdaptiveNewFeatsThreshold(N, desired_num_features);
725 
726  // Use KLT response instead of the OpenCV's original "response" field:
727  {
728  const unsigned int max_x = img_width - KLT_response_half_win;
729  const unsigned int max_y = img_height - KLT_response_half_win;
730  for (size_t i = 0; i < N; i++)
731  {
732  const unsigned int x = m_newly_detected_feats[i].pt.x;
733  const unsigned int y = m_newly_detected_feats[i].pt.y;
734  if (x > KLT_response_half_win && y > KLT_response_half_win &&
735  x < max_x && y < max_y)
736  m_newly_detected_feats[i].response =
737  cur_gray.KLT_response(x, y, KLT_response_half_win);
738  else
739  m_newly_detected_feats[i].response = 0; // Out of bounds
740  }
741  }
742 
743  // Sort them by "response": It's ~100 times faster to sort a list of
744  // indices "sorted_indices" than sorting directly the actual list
745  // of features "m_newly_detected_feats"
746  std::vector<size_t> sorted_indices(N);
747  for (size_t i = 0; i < N; i++) sorted_indices[i] = i;
748 
749  std::sort(
750  sorted_indices.begin(), sorted_indices.end(),
751  KeypointResponseSorter<TSimpleFeatureList>(m_newly_detected_feats));
752 
753  // For each new good feature, add it to the list of tracked ones only if
754  // it's pretty
755  // isolated:
756 
757  const size_t nNewToCheck = std::min(size_t(1500), N);
758  const double threshold_sqr_dist_to_add_new =
759  square(threshold_dist_to_add_new);
760  const size_t maxNumFeatures =
761  extra_params.getWithDefaultVal("add_new_feat_max_features", 100);
762  const size_t patchSize =
763  extra_params.getWithDefaultVal("add_new_feat_patch_size", 11);
764 
765  const float minimum_KLT_response_to_add =
766  extra_params.getWithDefaultVal("minimum_KLT_response_to_add", 10);
767 
768  // Do it:
770  featureList, m_newly_detected_feats, sorted_indices, nNewToCheck,
771  maxNumFeatures, minimum_KLT_response_to_add,
772  threshold_sqr_dist_to_add_new, patchSize, cur_gray,
773  max_feat_ID_at_input);
774 
775  m_timlog.leave("[CGenericFeatureTracker] add new features");
776  }
777 
778  m_timlog.leave(
779  "[CGenericFeatureTracker::trackFeatures] Complete iteration");
780 
781 } // end of CGenericFeatureTracker::trackFeatures
782 
784  const CImage& old_img, const CImage& new_img, CFeatureList& featureList)
785 {
786  internal_trackFeatures<CFeatureList>(old_img, new_img, featureList);
787 }
788 
790  const CImage& old_img, const CImage& new_img,
791  TSimpleFeatureList& featureList)
792 {
793  internal_trackFeatures<TSimpleFeatureList>(old_img, new_img, featureList);
794 }
795 
797  const CImage& old_img, const CImage& new_img,
798  TSimpleFeaturefList& featureList)
799 {
800  internal_trackFeatures<TSimpleFeaturefList>(old_img, new_img, featureList);
801 }
802 
804  const size_t nNewlyDetectedFeats, const size_t desired_num_features)
805 {
806  const size_t hysteresis_min_num_feats = desired_num_features * 0.9;
807  const size_t hysteresis_max_num_feats = desired_num_features * 1.1;
808 
809  if (nNewlyDetectedFeats < hysteresis_min_num_feats)
810  m_detector_adaptive_thres = std::max(
811  2.0, std::min(
812  m_detector_adaptive_thres - 1.0,
813  m_detector_adaptive_thres * 0.8));
814  else if (nNewlyDetectedFeats > hysteresis_max_num_feats)
815  m_detector_adaptive_thres = std::max(
816  m_detector_adaptive_thres + 1.0, m_detector_adaptive_thres * 1.2);
817 }
818 
819 /*------------------------------------------------------------
820  checkTrackedFeatures
821 -------------------------------------------------------------*/
823  CFeatureList& leftList, CFeatureList& rightList,
824  vision::TMatchingOptions options)
825 {
826  ASSERT_(leftList.size() == rightList.size());
827 
828  // std::cout << std::endl << "Tracked features checking ..." << std::endl;
829 
830  CFeatureList::iterator itLeft, itRight;
831  size_t u, v;
832  double res;
833 
834  for (itLeft = leftList.begin(), itRight = rightList.begin();
835  itLeft != leftList.end();)
836  {
837  bool delFeat = false;
838  if ((*itLeft)->x < 0 || (*itLeft)->y < 0 || // Out of bounds
839  (*itRight)->x < 0 || (*itRight)->y < 0 || // Out of bounds
840  fabs((*itLeft)->y - (*itRight)->y) >
841  options
842  .epipolar_TH) // Not fulfillment of the epipolar constraint
843  {
844  // Show reason
845  std::cout << "Bad tracked match:";
846  if ((*itLeft)->x < 0 || (*itLeft)->y < 0 || (*itRight)->x < 0 ||
847  (*itRight)->y < 0)
848  std::cout << " Out of bounds: (" << (*itLeft)->x << ","
849  << (*itLeft)->y << " & (" << (*itRight)->x << ","
850  << (*itRight)->y << ")" << std::endl;
851 
852  if (fabs((*itLeft)->y - (*itRight)->y) > options.epipolar_TH)
853  std::cout << " Bad row checking: "
854  << fabs((*itLeft)->y - (*itRight)->y) << std::endl;
855 
856  delFeat = true;
857  }
858  else
859  {
860  // Compute cross correlation:
862  (*itLeft)->patch, (*itRight)->patch, u, v, res);
863 
864  if (res < options.minCC_TH)
865  {
866  std::cout << "Bad tracked match (correlation failed):"
867  << " CC Value: " << res << std::endl;
868  delFeat = true;
869  }
870  } // end if
871 
872  if (delFeat) // Erase the pair of features
873  {
874  itLeft = leftList.erase(itLeft);
875  itRight = rightList.erase(itRight);
876  }
877  else
878  {
879  itLeft++;
880  itRight++;
881  }
882  } // end for
883 } // end checkTrackedFeatures
884 
885 /*-------------------------------------------------------------
886  filterBadCorrsByDistance
887 -------------------------------------------------------------*/
889  TMatchingPairList& feat_list, unsigned int numberOfSigmas)
890 {
891  ASSERT_(numberOfSigmas > 0);
892  // MRPT_UNUSED_PARAM( numberOfSigmas );
893  MRPT_START
894 
896  CMatrix dist;
897  double v_mean, v_std;
898  unsigned int count = 0;
899 
900  dist.setSize(feat_list.size(), 1);
901  // v_mean.resize(1);
902  // v_std.resize(1);
903 
904  // Compute mean and standard deviation of the distance
905  for (itPair = feat_list.begin(); itPair != feat_list.end();
906  itPair++, count++)
907  {
908  // cout << "(" << itPair->other_x << "," << itPair->other_y << "," <<
909  // itPair->this_z << ")" << "- (" << itPair->this_x << "," <<
910  // itPair->this_y << "," << itPair->other_z << "): ";
911  // cout << sqrt( square( itPair->other_x - itPair->this_x ) + square(
912  // itPair->other_y - itPair->this_y ) + square( itPair->other_z -
913  // itPair->this_z ) ) << endl;
914  dist(count, 0) = sqrt(
915  square(itPair->other_x - itPair->this_x) +
916  square(itPair->other_y - itPair->this_y) +
917  square(itPair->other_z - itPair->this_z));
918  }
919 
920  dist.meanAndStdAll(v_mean, v_std);
921 
922  cout << endl
923  << "*****************************************************" << endl;
924  cout << "Mean: " << v_mean << " - STD: " << v_std << endl;
925  cout << endl
926  << "*****************************************************" << endl;
927 
928  // Filter out bad points
929  unsigned int idx = 0;
930  // for( int idx = (int)feat_list.size()-1; idx >= 0; idx-- )
931  for (itPair = feat_list.begin(); itPair != feat_list.end(); idx++)
932  {
933  // if( dist( idx, 0 ) > 1.2 )
934  if (fabs(dist(idx, 0) - v_mean) > v_std * numberOfSigmas)
935  {
936  cout << "Outlier deleted: " << dist(idx, 0) << " vs "
937  << v_std * numberOfSigmas << endl;
938  itPair = feat_list.erase(itPair);
939  }
940  else
941  itPair++;
942  }
943 
944  MRPT_END
945 } // end filterBadCorrsByDistance
void trackFeatures_addNewFeats(FEATLIST &featureList, const TSimpleFeatureList &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)
const T & get_unsafe(size_t row, size_t col) const
Fast but unsafe method to read a value from the matrix.
std::shared_ptr< CFeature > Ptr
Definition: CFeature.h:58
GLuint GLuint GLsizei count
Definition: glext.h:3528
Helper class: KD-tree search class for vector<KeyPoint>: Call mark_as_outdated() to force rebuilding ...
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
#define min(a, b)
Declares a matrix of booleans (non serializable).
void trackFeatures_updatePatch< TSimpleFeaturefList >(TSimpleFeaturefList &featureList, const CImage &cur_gray)
Definition: tracking.cpp:179
void trackFeatures(const mrpt::utils::CImage &old_img, const mrpt::utils::CImage &new_img, TSimpleFeatureList &inout_featureList)
Perform feature tracking from "old_img" to "new_img", with a (possibly empty) list of previously trac...
Definition: tracking.cpp:789
A class for storing images as grayscale or RGB bitmaps.
Definition: CImage.h:118
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)
Definition: tracking.cpp:458
TFeatureTrackStatus track_status
featKLT, featHarris, featSURF, featBeacon
Definition: CFeature.h:69
size_t size() const
Definition: CFeature.h:387
#define THROW_EXCEPTION(msg)
A pair (x,y) of pixel coordinates (integer resolution).
Definition: TPixelCoord.h:38
GLintptr offset
Definition: glext.h:3925
Scalar * iterator
Definition: eigen_plugins.h:26
STL namespace.
float epipolar_TH
Epipolar constraint (rows of pixels)
static void detectFeatures_SSE2_FASTER12(const mrpt::utils::CImage &img, TSimpleFeatureList &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.
void filterBadCorrsByDistance(mrpt::utils::TMatchingPairList &list, unsigned int numberOfSigmas)
Filter bad correspondences by distance ...
Definition: tracking.cpp:888
float y
Coordinates in the image.
Definition: CFeature.h:61
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value...
TFeatureTrackStatus track_status
Status of the feature tracking process.
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:55
virtual void trackFeatures_impl(const mrpt::utils::CImage &old_img, const mrpt::utils::CImage &new_img, TSimpleFeaturefList &inout_featureList)
The tracking method implementation, to be implemented in children classes.
Definition: tracking.cpp:563
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_)
Definition: tracking.cpp:76
FAST feature detector, OpenCV&#39;s implementation ("Faster and better: A machine learning approac...
Inactive (right after detection, and before being tried to track)
A helper struct to sort keypoints by their response: It can be used with these types: ...
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
size_t getWidth() const override
Returns the width of the image in pixels.
Definition: CImage.cpp:869
#define MRPT_END
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...
Definition: CImage.cpp:2608
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
void trackFeatures_addNewFeats< TSimpleFeaturefList >(TSimpleFeaturefList &featureList, const TSimpleFeatureList &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)
Definition: tracking.cpp:438
void trackFeatures_updatePatch< TSimpleFeatureList >(TSimpleFeatureList &featureList, const CImage &cur_gray)
Definition: tracking.cpp:171
void openCV_cross_correlation(const mrpt::utils::CImage &img, const mrpt::utils::CImage &patch_img, size_t &x_max, size_t &y_max, double &max_val, int x_search_ini=-1, int y_search_ini=-1, int x_search_size=-1, int y_search_size=-1)
Computes the correlation between this image and another one, encapsulating the openCV function cvMatc...
A list of TMatchingPair.
Definition: TMatchingPair.h:93
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...
Definition: tracking.cpp:803
size_t getHeight() const override
Returns the height of the image in pixels.
Definition: CImage.cpp:897
void trackFeatures_addNewFeats< TSimpleFeatureList >(TSimpleFeatureList &featureList, const TSimpleFeatureList &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)
Definition: tracking.cpp:425
Classes for computer vision, detectors, features, etc.
A generic 2D feature from an image, extracted with CFeatureExtraction Each feature may have one or mo...
Definition: CFeature.h:53
uint8_t octave
The image octave the image was found in: 0=original image, 1=1/2 image, 2=1/4 image, etc.
iterator erase(const iterator &it)
Definition: CFeature.h:380
uint64_t TFeatureID
Definition of a feature ID.
A list of visual features, to be used as output by detectors, as input/output by trackers, etc.
Definition: CFeature.h:305
Unable to track this feature (mismatch is too high for the given tracking window: lack of texture...
void checkTrackedFeatures(CFeatureList &leftList, CFeatureList &rightList, vision::TMatchingOptions options)
Search for correspondences which are not in the same row and deletes them ...
Definition: tracking.cpp:822
float response
process (old name: KLT_status)
Definition: CFeature.h:71
#define MRPT_START
const GLdouble * v
Definition: glext.h:3678
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void trackFeatures_addNewFeats< CFeatureList >(CFeatureList &featureList, const TSimpleFeatureList &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)
Definition: tracking.cpp:196
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)
void trackFeatures_addNewFeats_simple_list(FEAT_LIST &featureList, const TSimpleFeatureList &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)
Definition: tracking.cpp:254
TFeatureID ID
ID of the feature.
size_t trackFeatures_deleteOOB(FEATLIST &trackedFeats, const size_t img_width, const size_t img_height, const int MIN_DIST_MARGIN_TO_STOP_TRACKING)
pixel_coords_t pt
Coordinates in the image.
float response
A measure of the "goodness" of the feature (typically, the KLT_response value)
A structure containing options for the matching.
A simple structure for representing one image feature (without descriptor nor patch) - This is the te...
void trackFeatures_updatePatch< CFeatureList >(CFeatureList &featureList, const CImage &cur_gray)
Definition: tracking.cpp:142
_u8 status
Definition: rplidar_cmd.h:20
#define ASSERT_(f)
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:25
TInternalFeatList::iterator iterator
Definition: CFeature.h:366
GLenum GLint GLint y
Definition: glext.h:3538
float minCC_TH
Minimum Value of the Cross Correlation.
void setSize(size_t row, size_t col, bool zeroNewElements=false)
Changes the size of matrix, maintaining the previous contents.
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)
Definition: tracking.cpp:40
mrpt::utils::CImage patch
A patch of the image surrounding the feature.
Definition: CFeature.h:64
void trackFeatures_checkResponses< TSimpleFeatureList >(TSimpleFeatureList &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)
Definition: tracking.cpp:117
GLuint res
Definition: glext.h:7268
GLenum GLint x
Definition: glext.h:3538
Feature fell Out Of Bounds (out of the image limits, too close to image borders)
This class is a "CSerializable" wrapper for "CMatrixFloat".
Definition: CMatrix.h:25
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)
Definition: tracking.cpp:522
void trackFeatures_checkResponses< TSimpleFeaturefList >(TSimpleFeaturefList &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)
Definition: tracking.cpp:127
void internal_trackFeatures(const mrpt::utils::CImage &old_img, const mrpt::utils::CImage &new_img, FEATLIST &inout_featureList)
Perform feature tracking from "old_img" to "new_img", with a (possibly empty) list of previously trac...
Definition: tracking.cpp:586
void fillAll(const T &val)



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019