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