MRPT  1.9.9
CFeatureExtraction_FASTER.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "vision-precomp.h" // Precompiled headers
11 
13 
14 // Universal include for all versions of OpenCV
15 #include <mrpt/otherlibs/do_opencv_includes.h>
16 #include <numeric> // iota
17 
18 #if MRPT_HAS_OPENCV
20 #endif
21 
22 using namespace mrpt;
23 using namespace mrpt::vision;
24 using namespace mrpt::img;
25 using namespace mrpt::img;
26 using namespace mrpt::system;
27 using namespace std;
28 
29 // ------------ SSE2-optimized implementations of FASTER -------------
31  const CImage& img, TKeyPointList& corners, const int threshold,
32  bool append_to_list, uint8_t octave,
33  std::vector<size_t>* out_feats_index_by_row)
34 {
35 #if MRPT_HAS_OPENCV
36  ASSERT_(!img.isColor());
37  if (!append_to_list) corners.clear();
38 
40  img.asCvMat<cv::Mat>(SHALLOW_COPY), corners, threshold, octave,
41  out_feats_index_by_row);
42 #else
43  THROW_EXCEPTION("MRPT built without OpenCV support!");
44 #endif
45 }
47  const CImage& img, TKeyPointList& corners, const int threshold,
48  bool append_to_list, uint8_t octave,
49  std::vector<size_t>* out_feats_index_by_row)
50 {
51 #if MRPT_HAS_OPENCV
52  ASSERT_(!img.isColor());
53  if (!append_to_list) corners.clear();
54 
56  img.asCvMat<cv::Mat>(SHALLOW_COPY), corners, threshold, octave,
57  out_feats_index_by_row);
58 #else
59  THROW_EXCEPTION("MRPT built without OpenCV support!");
60 #endif
61 }
63  const CImage& img, TKeyPointList& corners, const int threshold,
64  bool append_to_list, uint8_t octave,
65  std::vector<size_t>* out_feats_index_by_row)
66 {
67 #if MRPT_HAS_OPENCV
68  ASSERT_(!img.isColor());
69  if (!append_to_list) corners.clear();
70 
72  img.asCvMat<cv::Mat>(SHALLOW_COPY), corners, threshold, octave,
73  out_feats_index_by_row);
74 #else
75  THROW_EXCEPTION("MRPT built without OpenCV support!");
76 #endif
77 }
78 
79 // N_fast = 9, 10, 12
81  const int N_fast, const mrpt::img::CImage& inImg, CFeatureList& feats,
82  unsigned int init_ID, unsigned int nDesiredFeatures, const TImageROI& ROI)
83 {
84  MRPT_UNUSED_PARAM(ROI);
86 
87  CTimeLoggerEntry tle(profiler, "extractFeaturesFASTER_N");
88 
89 #if MRPT_HAS_OPENCV
90  // Make sure we operate on a gray-scale version of the image:
91  const CImage inImg_gray(inImg, FAST_REF_OR_CONVERT_TO_GRAY);
92  const cv::Mat& img = inImg_gray.asCvMatRef();
93 
94  TKeyPointList corners;
95  TKeyPointMethod type_of_this_feature;
96 
97  switch (N_fast)
98  {
99  case 9:
101  img, corners, options.FASTOptions.threshold, 0, nullptr);
102  type_of_this_feature = featFASTER9;
103  break;
104  case 10:
106  img, corners, options.FASTOptions.threshold, 0, nullptr);
107  type_of_this_feature = featFASTER10;
108  break;
109  case 12:
111  img, corners, options.FASTOptions.threshold, 0, nullptr);
112  type_of_this_feature = featFASTER12;
113  break;
114  default:
116  "Only the 9,10,12 FASTER detectors are implemented.");
117  };
118 
119  CTimeLoggerEntry tle2(profiler, "extractFeaturesFASTER_N.fillFeatsStruct");
120 
121  // *All* the features have been extracted.
122  const size_t N = corners.size();
123 
124  // Now:
125  // 1) Sort them by "response": It's ~100 times faster to sort a list of
126  // indices "sorted_indices" than sorting directly the actual list of
127  // features "corners"
128  std::vector<size_t> sorted_indices(N);
129  std::iota(sorted_indices.begin(), sorted_indices.end(), 0);
130 
131  // Use KLT response
132  // If the user wants us to limit the number of features, we need to do it
133  // according to some quality measure
134  if (options.FASTOptions.use_KLT_response || nDesiredFeatures != 0)
135  {
136  const auto KLT_half_win =
137  options.FASTOptions.KLT_response_half_win_size;
138  const auto max_x =
139  static_cast<int>(inImg_gray.getWidth() - 1 - KLT_half_win);
140  const auto max_y =
141  static_cast<int>(inImg_gray.getHeight() - 1 - KLT_half_win);
142 
143  for (size_t i = 0; i < N; i++)
144  {
145  const auto x = corners[i].pt.x;
146  const auto y = corners[i].pt.y;
147  if (x > KLT_half_win && y > KLT_half_win && x <= max_x &&
148  y <= max_y)
149  corners[i].response =
150  inImg_gray.KLT_response(x, y, KLT_half_win);
151  else
152  corners[i].response = -100;
153  }
154 
155  std::sort(
156  sorted_indices.begin(), sorted_indices.end(),
158  }
159  else
160  {
161  for (size_t i = 0; i < N; i++) corners[i].response = 0;
162  }
163 
164  // 2) Filter by "min-distance" (in options.FASTOptions.min_distance)
165  // 3) Convert to MRPT CFeatureList format.
166  // Steps 2 & 3 are done together in the while() below.
167  // The "min-distance" filter is done by means of a 2D binary matrix where
168  // each cell is marked when one
169  // feature falls within it. This is not exactly the same than a pure
170  // "min-distance" but is pretty close
171  // and for large numbers of features is much faster than brute force search
172  // of kd-trees.
173  // (An intermediate approach would be the creation of a mask image updated
174  // for each accepted feature, etc.)
175 
176  const bool do_filter_min_dist = options.FASTOptions.min_distance > 1;
177 
178  // Used half the min-distance since we'll later mark as occupied the ranges
179  // [i-1,i+1] for a feature at "i"
180  const unsigned int occupied_grid_cell_size =
181  options.FASTOptions.min_distance / 2.0;
182  const float occupied_grid_cell_size_inv = 1.0f / occupied_grid_cell_size;
183 
184  unsigned int grid_lx =
185  !do_filter_min_dist
186  ? 1
187  : (unsigned int)(1 + inImg.getWidth() * occupied_grid_cell_size_inv);
188  unsigned int grid_ly =
189  !do_filter_min_dist
190  ? 1
191  : (unsigned int)(1 + inImg.getHeight() * occupied_grid_cell_size_inv);
192 
193  // See the comments above for an explanation.
194  mrpt::math::CMatrixBool occupied_sections(grid_lx, grid_ly);
195  occupied_sections.fill(false);
196 
197  unsigned int nMax =
198  (nDesiredFeatures != 0 && N > nDesiredFeatures) ? nDesiredFeatures : N;
199  const int offset = (int)this->options.patchSize / 2 + 1;
200  const int size_2 = options.patchSize / 2;
201  const size_t imgH = inImg.getHeight();
202  const size_t imgW = inImg.getWidth();
203  unsigned int i = 0;
204  unsigned int cont = 0;
205  TFeatureID nextID = init_ID;
206 
207  if (!options.addNewFeatures) feats.clear();
208 
209  while (cont != nMax && i != N)
210  {
211  // Take the next feature from the ordered list of good features:
212  const TKeyPoint& feat = corners[sorted_indices[i]];
213  i++;
214 
215  // Patch out of the image??
216  const int xBorderInf = feat.pt.x - size_2;
217  const int xBorderSup = feat.pt.x + size_2;
218  const int yBorderInf = feat.pt.y - size_2;
219  const int yBorderSup = feat.pt.y + size_2;
220 
221  if (!(xBorderSup < (int)imgW && xBorderInf > 0 &&
222  yBorderSup < (int)imgH && yBorderInf > 0))
223  continue; // nope, skip.
224 
225  if (do_filter_min_dist)
226  {
227  // Check the min-distance:
228  const auto sect_ix =
229  size_t(feat.pt.x * occupied_grid_cell_size_inv);
230  const auto sect_iy =
231  size_t(feat.pt.y * occupied_grid_cell_size_inv);
232 
233  if (occupied_sections(sect_ix, sect_iy))
234  continue; // Already occupied! skip.
235 
236  // Mark section as occupied
237  occupied_sections(sect_ix, sect_iy) = true;
238  if (sect_ix > 0) occupied_sections(sect_ix - 1, sect_iy) = true;
239  if (sect_iy > 0) occupied_sections(sect_ix, sect_iy - 1) = true;
240  if (sect_ix < grid_lx - 1)
241  occupied_sections(sect_ix + 1, sect_iy) = true;
242  if (sect_iy < grid_ly - 1)
243  occupied_sections(sect_ix, sect_iy + 1) = true;
244  }
245 
246  // All tests passed: add new feature:
247  CFeature ft;
248  ft.type = type_of_this_feature;
249  ft.keypoint.ID = nextID++;
250  ft.keypoint.pt.x = feat.pt.x;
251  ft.keypoint.pt.y = feat.pt.y;
252  ft.response = feat.response;
253  ft.orientation = 0;
254  ft.keypoint.octave = 1;
255  ft.patchSize = options.patchSize; // The size of the feature patch
256 
257  if (options.patchSize > 0)
258  {
259  ft.patch.emplace();
260  inImg.extract_patch(
261  *ft.patch, round(feat.pt.x) - offset, round(feat.pt.y) - offset,
262  options.patchSize,
263  options.patchSize); // Image patch surronding the feature
264  }
265  feats.push_back(ft);
266  ++cont;
267  }
268 
269 #endif
270  MRPT_END
271 }
Shallow copy: the copied object is a reference to the original one.
Definition: img/CImage.h:74
#define MRPT_START
Definition: exceptions.h:241
uint64_t TFeatureID
Definition of a feature ID.
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
A safe way to call enter() and leave() of a mrpt::system::CTimeLogger upon construction and destructi...
TKeyPointMethod type
Keypoint method used to detect this feature.
Definition: CFeature.h:73
void fill(const Scalar &val)
GLintptr offset
Definition: glext.h:3936
void fast_corner_detect_10(const cv::Mat &I, TKeyPointList &corners, int barrier, uint8_t octave, std::vector< size_t > *out_feats_index_by_row)
cv::Mat & asCvMatRef()
Get a reference to the internal cv::Mat, which can be resized, etc.
Definition: CImage.cpp:233
size_t getHeight() const override
Returns the height of the image in pixels.
Definition: CImage.cpp:878
STL namespace.
TFeatureID ID
ID of the feature.
Definition: TKeyPoint.h:39
Simple structure for image key points.
Definition: TKeyPoint.h:28
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.
unsigned char uint8_t
Definition: rptypes.h:44
A helper struct to sort keypoints by their response: It can be used with these types: ...
Definition: TKeyPoint.h:288
A structure for defining a ROI within an image.
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
void push_back(const CFeature &f)
Definition: CFeature.h:369
size_t getWidth() const override
Returns the width of the image in pixels.
Definition: CImage.cpp:847
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:1905
TKeyPointf keypoint
Definition: CFeature.h:64
std::optional< mrpt::img::CImage > patch
A patch of the image surrounding the feature.
Definition: CFeature.h:67
void fast_corner_detect_9(const cv::Mat &I, TKeyPointList &corners, int barrier, uint8_t octave, std::vector< size_t > *out_feats_index_by_row)
GLint GLvoid * img
Definition: glext.h:3769
TKeyPointMethod
Types of key point detectors.
Classes for computer vision, detectors, features, etc.
Definition: CDifodo.h:17
A generic 2D feature from an image, extracted with CFeatureExtraction Each feature may have one or mo...
Definition: CFeature.h:53
FASTER-9 detector, Edward Rosten&#39;s libcvd, SSE2 optimized.
A list of visual features, to be used as output by detectors, as input/output by trackers, etc.
Definition: CFeature.h:275
void extractFeaturesFASTER_N(const int N, const mrpt::img::CImage &img, CFeatureList &feats, unsigned int init_ID=0, unsigned int nDesiredFeatures=0, const TImageROI &ROI=TImageROI())
Edward&#39;s "FASTER & Better" detector, N=9,10,12.
float response
A measure of the "goodness" of the feature.
Definition: CFeature.h:79
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
FASTER-9 detector, Edward Rosten&#39;s libcvd, SSE2 optimized.
#define MRPT_END
Definition: exceptions.h:245
uint8_t octave
The image octave the image was found in: 0=original image, 1=1/2 image, 2=1/4 image, etc.
Definition: TKeyPoint.h:49
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 extract_patch(CImage &patch, const unsigned int col=0, const unsigned int row=0, const unsigned int width=1, const unsigned int height=1) const
Extract a patch from this image, saveing it into "patch" (its previous contents will be overwritten)...
Definition: CImage.cpp:1184
GLenum GLint GLint y
Definition: glext.h:3542
float orientation
Main orientation of the feature.
Definition: CFeature.h:81
GLenum GLint x
Definition: glext.h:3542
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.
This template class provides the basic functionality for a general 2D any-size, resizable container o...
float response
A measure of the "goodness" of the feature (typically, the KLT_response value)
Definition: TKeyPoint.h:46
uint16_t patchSize
Size of the patch (patchSize x patchSize) (it must be an odd number)
Definition: CFeature.h:70
void fast_corner_detect_12(const cv::Mat &I, TKeyPointList &corners, int barrier, uint8_t octave, std::vector< size_t > *out_feats_index_by_row)
pixel_coords_t pt
Coordinates in the image.
Definition: TKeyPoint.h:36
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:147
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
Definition: common.h:186
FASTER-9 detector, Edward Rosten&#39;s libcvd, SSE2 optimized.
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:23



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019