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



Page generated by Doxygen 1.8.14 for MRPT 1.5.7 Git: 5902e14cc Wed Apr 24 15:04:01 2019 +0200 at lun oct 28 01:39:17 CET 2019