Main MRPT website > C++ reference for MRPT 1.9.9
CFeatureExtraction_ORB.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::utils;
19 using namespace mrpt::vision;
20 using namespace mrpt::system;
21 using namespace std;
22 
23 /************************************************************************************************
24 * extractFeaturesORB
25 **
26 ************************************************************************************************/
27 void CFeatureExtraction::extractFeaturesORB(
28  const mrpt::utils::CImage& inImg, CFeatureList& feats,
29  const unsigned int init_ID, const unsigned int nDesiredFeatures,
30  const TImageROI& ROI) const
31 {
32  MRPT_UNUSED_PARAM(ROI);
34 
35 #if MRPT_HAS_OPENCV
36 #if MRPT_OPENCV_VERSION_NUM < 0x240
37  THROW_EXCEPTION("This function requires OpenCV > 2.4.0")
38 #else
39 
40  using namespace cv;
41 
42  vector<KeyPoint> cv_feats; // OpenCV keypoint output vector
43  Mat cv_descs; // OpenCV descriptor output
44 
45  const bool use_precomputed_feats = feats.size() > 0;
46 
47  if (use_precomputed_feats)
48  {
49  cv_feats.resize(feats.size());
50  for (size_t k = 0; k < cv_feats.size(); ++k)
51  {
52  cv_feats[k].pt.x = feats[k]->x;
53  cv_feats[k].pt.y = feats[k]->y;
54  }
55  }
56 
57  // Make sure we operate on a gray-scale version of the image:
58  const CImage inImg_gray(inImg, FAST_REF_OR_CONVERT_TO_GRAY);
59  const Mat cvImg = cv::cvarrToMat(inImg_gray.getAs<IplImage>());
60 
61 // The detector and descriptor
62 #if MRPT_OPENCV_VERSION_NUM < 0x300
63  Ptr<Feature2D> orb = Algorithm::create<Feature2D>("Feature2D.ORB");
64  orb->operator()(cvImg, Mat(), cv_feats, cv_descs, use_precomputed_feats);
65 #else
66  const size_t n_feats_2_extract =
67  nDesiredFeatures == 0 ? 1000 : 3 * nDesiredFeatures;
68  Ptr<cv::ORB> orb = cv::ORB::create(
69  n_feats_2_extract, options.ORBOptions.scale_factor,
70  options.ORBOptions.n_levels);
71  orb->detectAndCompute(
72  cvImg, Mat(), cv_feats, cv_descs, use_precomputed_feats);
73 #endif
74 
75  const size_t n_feats = cv_feats.size();
76 
77  // if we had input features, just convert cv_feats to CFeatures and return
78  const unsigned int patch_size_2 = options.patchSize / 2;
79  unsigned int f_id = init_ID;
80  if (use_precomputed_feats)
81  {
82  for (size_t k = 0; k < n_feats; ++k)
83  {
84  feats[k]->descriptors.ORB.resize(cv_descs.cols);
85  for (int m = 0; m < cv_descs.cols; ++m)
86  feats[k]->descriptors.ORB[m] =
87  cv_descs.at<uchar>(k, m); // to do: memcopy
88 
89  /*
90  feats[k].response = cv_feats[k].response;
91  feats[k].scale = cv_feats[k].size;
92  feats[k].angle = cv_feats[k].orientation;
93  feats[k].ID = f_id++;
94  */
95  feats[k]->type = featORB;
96 
97  if (options.ORBOptions.extract_patch && options.patchSize > 0)
98  {
99  inImg.extract_patch(
100  feats[k]->patch, round(feats[k]->x) - patch_size_2,
101  round(feats[k]->y) - patch_size_2, options.patchSize,
102  options.patchSize);
103  }
104  }
105  return;
106  }
107 
108  // 1) Sort the fearues by "response": It's ~100 times faster to sort a list
109  // of
110  // indices "sorted_indices" than sorting directly the actual list of
111  // features "cv_feats"
112  std::vector<size_t> sorted_indices(n_feats);
113  for (size_t i = 0; i < n_feats; i++) sorted_indices[i] = i;
114  std::sort(
115  sorted_indices.begin(), sorted_indices.end(),
117 
118  // 2) Filter by "min-distance" (in options.ORBOptions.min_distance)
119  // 3) Convert to MRPT CFeatureList format.
120  // Steps 2 & 3 are done together in the while() below.
121  // The "min-distance" filter is done by means of a 2D binary matrix where
122  // each cell is marked when one
123  // feature falls within it. This is not exactly the same than a pure
124  // "min-distance" but is pretty close
125  // and for large numbers of features is much faster than brute force search
126  // of kd-trees.
127  // (An intermediate approach would be the creation of a mask image updated
128  // for each accepted feature, etc.)
129 
130  const bool do_filter_min_dist = options.ORBOptions.min_distance > 1;
131  const unsigned int occupied_grid_cell_size =
132  options.ORBOptions.min_distance / 2.0;
133  const float occupied_grid_cell_size_inv = 1.0f / occupied_grid_cell_size;
134 
135  unsigned int grid_lx =
136  !do_filter_min_dist
137  ? 1
138  : (unsigned int)(1 + inImg.getWidth() * occupied_grid_cell_size_inv);
139  unsigned int grid_ly =
140  !do_filter_min_dist
141  ? 1
142  : (unsigned int)(1 + inImg.getHeight() * occupied_grid_cell_size_inv);
143 
144  mrpt::math::CMatrixBool occupied_sections(
145  grid_lx, grid_ly); // See the comments above for an explanation.
146  occupied_sections.fillAll(false);
147 
148  const size_t n_max_feats = nDesiredFeatures > 0
149  ? std::min(size_t(nDesiredFeatures), n_feats)
150  : n_feats;
151 
152  if (!options.addNewFeatures) feats.clear();
153  // feats.reserve( feats.size() + n_max_feats );
154 
155  const size_t imgH = inImg.getHeight();
156  const size_t imgW = inImg.getWidth();
157  size_t k = 0;
158  size_t c_feats = 0;
159  while (c_feats < n_max_feats && k < n_feats)
160  {
161  const size_t idx = sorted_indices[k++];
162  const KeyPoint& kp = cv_feats[idx];
163  if (options.ORBOptions.extract_patch && options.patchSize > 0)
164  {
165  // check image boundaries for extracting the patch
166  const int xBorderInf = (int)floor(kp.pt.x - patch_size_2);
167  const int xBorderSup = (int)floor(kp.pt.x + patch_size_2);
168  const int yBorderInf = (int)floor(kp.pt.y - patch_size_2);
169  const int yBorderSup = (int)floor(kp.pt.y + patch_size_2);
170 
171  if (!(xBorderSup < (int)imgW && xBorderInf > 0 &&
172  yBorderSup < (int)imgH && yBorderInf > 0))
173  continue; // nope, skip.
174  }
175 
176  if (do_filter_min_dist)
177  {
178  // Check the min-distance:
179  const size_t section_idx_x =
180  size_t(kp.pt.x * occupied_grid_cell_size_inv);
181  const size_t section_idx_y =
182  size_t(kp.pt.y * occupied_grid_cell_size_inv);
183 
184  if (occupied_sections(section_idx_x, section_idx_y))
185  continue; // Already occupied! skip.
186 
187  // Mark section as occupied
188  occupied_sections.set_unsafe(section_idx_x, section_idx_y, true);
189  if (section_idx_x > 0)
190  occupied_sections.set_unsafe(
191  section_idx_x - 1, section_idx_y, true);
192  if (section_idx_y > 0)
193  occupied_sections.set_unsafe(
194  section_idx_x, section_idx_y - 1, true);
195  if (section_idx_x < grid_lx - 1)
196  occupied_sections.set_unsafe(
197  section_idx_x + 1, section_idx_y, true);
198  if (section_idx_y < grid_ly - 1)
199  occupied_sections.set_unsafe(
200  section_idx_x, section_idx_y + 1, true);
201  }
202 
203  // All tests passed: add new feature:
204  CFeature::Ptr ft = mrpt::make_aligned_shared<CFeature>();
205  ft->type = featORB;
206  ft->ID = f_id++;
207  ft->x = kp.pt.x;
208  ft->y = kp.pt.y;
209  ft->response = kp.response;
210  ft->orientation = kp.angle;
211  ft->scale = kp.octave;
212  ft->patchSize = 0;
213 
214  // descriptor
215  ft->descriptors.ORB.resize(cv_descs.cols);
216  for (int m = 0; m < cv_descs.cols; ++m)
217  ft->descriptors.ORB[m] = cv_descs.at<uchar>(idx, m);
218 
219  if (options.ORBOptions.extract_patch && options.patchSize > 0)
220  {
221  ft->patchSize = options.patchSize; // The size of the feature patch
222 
223  inImg.extract_patch(
224  ft->patch, round(ft->x) - patch_size_2,
225  round(ft->y) - patch_size_2, options.patchSize,
226  options.patchSize); // Image patch surronding the feature
227  }
228 
229  feats.push_back(ft);
230  c_feats++;
231  }
232 #endif
233 #endif
234  MRPT_END
235 }
236 
237 void CFeatureExtraction::internal_computeORBDescriptors(
238  const CImage& in_img, CFeatureList& in_features) const
239 {
240 #if MRPT_HAS_OPENCV
241 #if MRPT_OPENCV_VERSION_NUM < 0x240
242  THROW_EXCEPTION("This function requires OpenCV > 2.4.0")
243 #else
244  using namespace cv;
245 
246  const size_t n_feats = in_features.size();
247  const CImage inImg_gray(in_img, FAST_REF_OR_CONVERT_TO_GRAY);
248 
249  // convert from CFeatureList to vector<KeyPoint>
250  vector<KeyPoint> cv_feats(n_feats);
251  for (size_t k = 0; k < n_feats; ++k)
252  {
253  KeyPoint& kp = cv_feats[k];
254  kp.pt.x = in_features[k]->x;
255  kp.pt.y = in_features[k]->y;
256  kp.angle = in_features[k]->orientation;
257  kp.size = in_features[k]->scale;
258  } // end-for
259 
260  Mat cvImg(cv::cvarrToMat(inImg_gray.getAs<IplImage>()));
261  Mat cv_descs;
262 
263 #if MRPT_OPENCV_VERSION_NUM < 0x300
264  Ptr<Feature2D> orb = Algorithm::create<Feature2D>("Feature2D.ORB");
265  orb->operator()(
266  cvImg, Mat(), cv_feats, cv_descs, true /* use_precomputed_feats */);
267 #else
268  Ptr<cv::ORB> orb = cv::ORB::create(
269  n_feats, options.ORBOptions.scale_factor, options.ORBOptions.n_levels);
270  orb->detectAndCompute(
271  cvImg, Mat(), cv_feats, cv_descs, true /* use_precomputed_feats */);
272 #endif
273 
274  // add descriptor to CFeatureList
275  for (size_t k = 0; k < n_feats; ++k)
276  {
277  in_features[k]->descriptors.ORB.resize(cv_descs.cols);
278  for (int i = 0; i < cv_descs.cols; ++i)
279  in_features[k]->descriptors.ORB[i] = cv_descs.at<uchar>(k, i);
280 
281  } // end-for
282 #endif
283 #endif
284 
285 } // end-internal_computeORBImageDescriptors
std::shared_ptr< CFeature > Ptr
Definition: CFeature.h:58
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).
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
size_t size() const
Definition: CFeature.h:387
#define THROW_EXCEPTION(msg)
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
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.
size_t getWidth() const override
Returns the width of the image in pixels.
Definition: CImage.cpp:869
void resize(size_t N)
Definition: CFeature.h:393
#define MRPT_END
#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.
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
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:25
GLenum GLint GLint y
Definition: glext.h:3538
ORB detector and descriptor, OpenCV&#39;s implementation ("ORB: an efficient alternative to SIFT o...
GLenum GLint x
Definition: glext.h:3538
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