Main MRPT website > C++ reference for MRPT 1.9.9
CFeatureExtraction_FAST.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 
13 
14 // Universal include for all versions of OpenCV
15 #include <mrpt/otherlibs/do_opencv_includes.h>
16 
17 using namespace mrpt;
18 using namespace mrpt::vision;
19 using namespace mrpt::system;
20 using namespace mrpt::utils;
21 using namespace mrpt::math;
22 using namespace std;
23 
24 /************************************************************************************************
25 * extractFeaturesFAST
26 **
27 ************************************************************************************************/
29  const mrpt::utils::CImage& inImg, CFeatureList& feats, unsigned int init_ID,
30  unsigned int nDesiredFeatures, const TImageROI& ROI,
31  const CMatrixBool* mask) const
32 {
33  MRPT_UNUSED_PARAM(ROI);
35 
36 #if MRPT_HAS_OPENCV
37 #if MRPT_OPENCV_VERSION_NUM < 0x210
38  THROW_EXCEPTION("This function requires OpenCV > 2.1.0")
39 #else
40 
41  using namespace cv;
42 
43  vector<KeyPoint> cv_feats; // The opencv keypoint output vector
44 
45  // Make sure we operate on a gray-scale version of the image:
46  const CImage inImg_gray(inImg, FAST_REF_OR_CONVERT_TO_GRAY);
47 
48 // JL: Instead of
49 // int aux = options.FASTOptions.threshold; ....
50 // It's better to use an adaptive threshold, controlled from our caller
51 // outside.
52 
53 #if MRPT_OPENCV_VERSION_NUM >= 0x211
54 
55  // cv::Mat *mask ;
56  // if( _mask )
57  // mask = static_cast<cv::Mat*>(_mask);
58 
59  const Mat theImg = cvarrToMat(inImg_gray.getAs<IplImage>());
60 
61  cv::Mat cvMask;
62  if (options.useMask)
63  {
64  cout << "using mask" << endl;
65  size_t maskW = mask->getColCount(), maskH = mask->getRowCount();
66  ASSERT_(
67  maskW == inImg_gray.getWidth() && maskH == inImg_gray.getHeight());
68 
69  // Convert Mask into CV type
70  cvMask = cv::Mat::ones(maskH, maskW, CV_8UC1);
71  for (int ii = 0; ii < int(maskW); ++ii)
72  for (int jj = 0; jj < int(maskH); ++jj)
73  {
74  if (!mask->get_unsafe(jj, ii))
75  {
76  cvMask.at<char>(ii, jj) = (char)0;
77  }
78  }
79  }
80 
81 #if MRPT_OPENCV_VERSION_NUM < 0x300
82  FastFeatureDetector fastDetector(
83  options.FASTOptions.threshold, options.FASTOptions.nonmax_suppression);
84  fastDetector.detect(theImg, cv_feats);
85 #else
86  Ptr<cv::FastFeatureDetector> fastDetector = cv::FastFeatureDetector::create(
87  options.FASTOptions.threshold, options.FASTOptions.nonmax_suppression);
88  fastDetector->detect(theImg, cv_feats);
89 #endif
90 
91 #elif MRPT_OPENCV_VERSION_NUM >= 0x210
92  FAST(
93  inImg_gray.getAs<IplImage>(), cv_feats, options.FASTOptions.threshold,
94  options.FASTOptions.nonmax_suppression);
95 #endif
96 
97  // *All* the features have been extracted.
98  const size_t N = cv_feats.size();
99 
100  // Use KLT response instead of the OpenCV's original "response" field:
101  if (options.FASTOptions.use_KLT_response)
102  {
103  const unsigned int KLT_half_win = 4;
104  const unsigned int max_x = inImg_gray.getWidth() - 1 - KLT_half_win;
105  const unsigned int max_y = inImg_gray.getHeight() - 1 - KLT_half_win;
106  for (size_t i = 0; i < N; i++)
107  {
108  const unsigned int x = cv_feats[i].pt.x;
109  const unsigned int y = cv_feats[i].pt.y;
110  if (x > KLT_half_win && y > KLT_half_win && x <= max_x &&
111  y <= max_y)
112  cv_feats[i].response =
113  inImg_gray.KLT_response(x, y, KLT_half_win);
114  else
115  cv_feats[i].response = -100;
116  }
117  }
118 
119  // Now:
120  // 1) Sort them by "response": It's ~100 times faster to sort a list of
121  // indices "sorted_indices" than sorting directly the actual list of
122  // features "cv_feats"
123  std::vector<size_t> sorted_indices(N);
124  for (size_t i = 0; i < N; i++) sorted_indices[i] = i;
125  std::sort(
126  sorted_indices.begin(), sorted_indices.end(),
128 
129  // 2) Filter by "min-distance" (in options.FASTOptions.min_distance)
130  // 3) Convert to MRPT CFeatureList format.
131  // Steps 2 & 3 are done together in the while() below.
132  // The "min-distance" filter is done by means of a 2D binary matrix where
133  // each cell is marked when one
134  // feature falls within it. This is not exactly the same than a pure
135  // "min-distance" but is pretty close
136  // and for large numbers of features is much faster than brute force search
137  // of kd-trees.
138  // (An intermediate approach would be the creation of a mask image updated
139  // for each accepted feature, etc.)
140 
141  const bool do_filter_min_dist = options.FASTOptions.min_distance > 1;
142 
143  // Used half the min-distance since we'll later mark as occupied the ranges
144  // [i-1,i+1] for a feature at "i"
145  const unsigned int occupied_grid_cell_size =
146  options.FASTOptions.min_distance / 2.0;
147  const float occupied_grid_cell_size_inv = 1.0f / occupied_grid_cell_size;
148 
149  unsigned int grid_lx =
150  !do_filter_min_dist
151  ? 1
152  : (unsigned int)(1 + inImg.getWidth() * occupied_grid_cell_size_inv);
153  unsigned int grid_ly =
154  !do_filter_min_dist
155  ? 1
156  : (unsigned int)(1 + inImg.getHeight() * occupied_grid_cell_size_inv);
157 
158  mrpt::math::CMatrixBool occupied_sections(
159  grid_lx, grid_ly); // See the comments above for an explanation.
160  occupied_sections.fillAll(false);
161 
162  unsigned int nMax =
163  (nDesiredFeatures != 0 && N > nDesiredFeatures) ? nDesiredFeatures : N;
164  const int offset = (int)this->options.patchSize / 2 + 1;
165  const size_t size_2 = options.patchSize / 2;
166  const size_t imgH = inImg.getHeight();
167  const size_t imgW = inImg.getWidth();
168  unsigned int i = 0;
169  unsigned int cont = 0;
170  TFeatureID nextID = init_ID;
171 
172  if (!options.addNewFeatures) feats.clear();
173 
174  while (cont != nMax && i != N)
175  {
176  // Take the next feature fromt the ordered list of good features:
177  const KeyPoint& kp = cv_feats[sorted_indices[i]];
178  i++;
179 
180  // Patch out of the image??
181  const int xBorderInf = (int)floor(kp.pt.x - size_2);
182  const int xBorderSup = (int)floor(kp.pt.x + size_2);
183  const int yBorderInf = (int)floor(kp.pt.y - size_2);
184  const int yBorderSup = (int)floor(kp.pt.y + size_2);
185 
186  if (!(xBorderSup < (int)imgW && xBorderInf > 0 &&
187  yBorderSup < (int)imgH && yBorderInf > 0))
188  continue; // nope, skip.
189 
190  if (do_filter_min_dist)
191  {
192  // Check the min-distance:
193  const size_t section_idx_x =
194  size_t(kp.pt.x * occupied_grid_cell_size_inv);
195  const size_t section_idx_y =
196  size_t(kp.pt.y * occupied_grid_cell_size_inv);
197 
198  if (occupied_sections(section_idx_x, section_idx_y))
199  continue; // Already occupied! skip.
200 
201  // Mark section as occupied
202  occupied_sections.set_unsafe(section_idx_x, section_idx_y, true);
203  if (section_idx_x > 0)
204  occupied_sections.set_unsafe(
205  section_idx_x - 1, section_idx_y, true);
206  if (section_idx_y > 0)
207  occupied_sections.set_unsafe(
208  section_idx_x, section_idx_y - 1, true);
209  if (section_idx_x < grid_lx - 1)
210  occupied_sections.set_unsafe(
211  section_idx_x + 1, section_idx_y, true);
212  if (section_idx_y < grid_ly - 1)
213  occupied_sections.set_unsafe(
214  section_idx_x, section_idx_y + 1, true);
215  }
216 
217  // All tests passed: add new feature:
218  CFeature::Ptr ft = mrpt::make_aligned_shared<CFeature>();
219  ft->type = featFAST;
220  ft->ID = nextID++;
221  ft->x = kp.pt.x;
222  ft->y = kp.pt.y;
223  ft->response = kp.response;
224  ft->orientation = kp.angle;
225  ft->scale = kp.octave;
226  ft->patchSize = options.patchSize; // The size of the feature patch
227 
228  if (options.patchSize > 0)
229  {
230  inImg.extract_patch(
231  ft->patch, round(ft->x) - offset, round(ft->y) - offset,
232  options.patchSize,
233  options.patchSize); // Image patch surronding the feature
234  }
235  feats.push_back(ft);
236  ++cont;
237  }
238 // feats.resize( cont ); // JL: really needed???
239 
240 #endif
241 #endif
242  MRPT_END
243 }
std::shared_ptr< CFeature > Ptr
Definition: CFeature.h:58
GLenum GLint GLuint mask
Definition: glext.h:4050
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
Declares a matrix of booleans (non serializable).
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
A class for storing images as grayscale or RGB bitmaps.
Definition: CImage.h:118
#define THROW_EXCEPTION(msg)
GLintptr offset
Definition: glext.h:3925
STL namespace.
const T * getAs() const
Returns a pointer to a const T* containing the image - the idea is to call like "img.getAs<IplImage>()" so we can avoid here including OpenCV&#39;s headers.
Definition: CImage.h:587
FAST feature detector, OpenCV&#39;s implementation ("Faster and better: A machine learning approac...
A helper struct to sort keypoints by their response: It can be used with these types: ...
A structure for defining a ROI within an image.
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.
size_t getHeight() const override
Returns the height of the image in pixels.
Definition: CImage.cpp:897
Classes for computer vision, detectors, features, etc.
uint64_t TFeatureID
Definition of a feature ID.
void set_unsafe(size_t row, size_t col, const T &v)
Fast but unsafe method to write a value in the matrix.
A list of visual features, to be used as output by detectors, as input/output by trackers, etc.
Definition: CFeature.h:305
#define MRPT_START
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
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:1367
#define ASSERT_(f)
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:25
GLenum GLint GLint y
Definition: glext.h:3538
GLenum GLint x
Definition: glext.h:3538
EIGEN_STRONG_INLINE void ones(const size_t row, const size_t col)
Resize matrix and set all elements to one.
Definition: eigen_plugins.h:86
void extractFeaturesFAST(const mrpt::utils::CImage &img, CFeatureList &feats, unsigned int init_ID=0, unsigned int nDesiredFeatures=0, const TImageROI &ROI=TImageROI(), const mrpt::math::CMatrixBool *mask=nullptr) const
Extract features from the image based on the FAST method.
void push_back(const CFeature::Ptr &f)
Definition: CFeature.h:399
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