Main MRPT website > C++ reference
MRPT logo
CFeature.h
Go to the documentation of this file.
1 /* +---------------------------------------------------------------------------+
2  | The Mobile Robot Programming Toolkit (MRPT) C++ library |
3  | |
4  | http://www.mrpt.org/ |
5  | |
6  | Copyright (C) 2005-2012 University of Malaga |
7  | |
8  | This software was written by the Machine Perception and Intelligent |
9  | Robotics Lab, University of Malaga (Spain). |
10  | Contact: Jose-Luis Blanco <jlblanco@ctima.uma.es> |
11  | |
12  | This file is part of the MRPT project. |
13  | |
14  | MRPT is free software: you can redistribute it and/or modify |
15  | it under the terms of the GNU General Public License as published by |
16  | the Free Software Foundation, either version 3 of the License, or |
17  | (at your option) any later version. |
18  | |
19  | MRPT is distributed in the hope that it will be useful, |
20  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
21  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22  | GNU General Public License for more details. |
23  | |
24  | You should have received a copy of the GNU General Public License |
25  | along with MRPT. If not, see <http://www.gnu.org/licenses/>. |
26  | |
27  +---------------------------------------------------------------------------+ */
28 #ifndef CFeature_H
29 #define CFeature_H
30 
31 #include <mrpt/utils/CImage.h>
33 #include <mrpt/math/CMatrix.h>
34 #include <mrpt/math/ops_matrices.h>
36 
37 #include <mrpt/vision/types.h>
39 
40 namespace mrpt
41 {
42  namespace vision
43  {
44  using namespace mrpt::utils;
45  using namespace mrpt::math;
46  using namespace std;
47 
48  class CFeatureList;
49  class CMatchedFeatureList;
50 
51  enum TListIdx
52  {
53  firstList = 0,
56  };
57 
58  /** \defgroup mrptvision_features Feature detection, descriptors and matching
59  * \ingroup mrpt_vision_grp
60  */
61 
62  /** \addtogroup mrptvision_features
63  @{ */
64 
65 
66  /****************************************************
67  Class CFEATURE
68  *****************************************************/
70 
71  /** A generic 2D feature from an image, extracted with \a CFeatureExtraction
72  * Each feature may have one or more descriptors (see \a descriptors), in addition to an image patch.
73  * The (Euclidean) distance between descriptors in a pair of features can be computed with descriptorDistanceTo,
74  * while the similarity of the patches is given by patchCorrelationTo.
75  *
76  * \sa CFeatureList, TSimpleFeature, TSimpleFeatureList
77  */
78  class VISION_IMPEXP CFeature : public mrpt::utils::CSerializable
79  {
80  friend class CFeatureList;
81  friend class CMatchedFeatureList;
82 
84 
85  public:
86  float x,y; //!< Coordinates in the image
87  TFeatureID ID; //!< ID of the feature
88  CImage patch; //!< A patch of the image surrounding the feature
89  uint16_t patchSize; //!< Size of the patch (patchSize x patchSize) (it must be an odd number)
90  TFeatureType type; //!< Type of the feature: featNotDefined, featSIFT, featKLT, featHarris, featSURF, featBeacon
91  TFeatureTrackStatus track_status; //!< Status of the feature tracking process (old name: KLT_status)
92  float response; //!< A measure of the "goodness" of the feature (old name: KLT_val)
93  float orientation; //!< Main orientation of the feature
94  float scale; //!< Feature scale into the scale space
95  uint8_t user_flags; //!< A field for any other flags needed by the user (this has not a predefined meaning)
96  uint16_t nTimesSeen; //!< Number of frames it has been seen in a sequence of images.
97  uint16_t nTimesNotSeen; //!< Number of frames it has not been seen in a sequence of images.
98  uint16_t nTimesLastSeen; //!< Number of frames since it was seen for the last time.
99 
100  double depth; //!< The estimated depth in 3D of this feature wrt the camera in the current frame
101  double initialDepth; //!< The estimated depth in 3D of this feature wrt the camera that took its image
102  TPoint3D p3D; //!< The estimated 3D point of this feature wrt its camera
103  deque<double> multiScales; //!< A set of scales where the multi-resolution descriptor has been computed
104  deque<vector<double> > multiOrientations; //!< A vector of main orientations (there is a vector of orientations for each scale)
105  deque<vector<vector<int32_t> > > multiHashCoeffs; //!< A set of vectors containing the coefficients for a HASH table of descriptors
106  bool isPointFeature() const; //!< Return false only for Blob detectors (SIFT, SURF)
107 
108  /** All the possible descriptors this feature may have */
110  {
111  TDescriptors(); // Initialization
112 
113  std::vector<uint8_t> SIFT; //!< Feature descriptor
114  std::vector<float> SURF; //!< Feature descriptor
115  std::vector<float> SpinImg; //!< The 2D histogram as a single row
116  uint16_t SpinImg_range_rows; //!< The number of rows (corresponding to range bins in the 2D histogram) of the original matrix from which SpinImg was extracted as a vector.
117  mrpt::math::CMatrix PolarImg; //!< A polar image centered at the interest point
118  mrpt::math::CMatrix LogPolarImg; //!< A log-polar image centered at the interest point
119  bool polarImgsNoRotation; //!< If set to true (manually, default=false) the call to "descriptorDistanceTo" will not consider all the rotations between polar image descriptors (PolarImg, LogPolarImg)
120  deque<vector<vector<int32_t> > > multiSIFTDescriptors; //!< A set of SIFT-like descriptors for each orientation and scale of the multiResolution feature (there is a vector of descriptors for each scale)
121 
122  bool hasDescriptorSIFT() const { return !SIFT.empty(); }; //!< Whether this feature has this kind of descriptor
123  bool hasDescriptorSURF() const { return !SURF.empty(); } //!< Whether this feature has this kind of descriptor
124  bool hasDescriptorSpinImg() const { return !SpinImg.empty(); }; //!< Whether this feature has this kind of descriptor
125  bool hasDescriptorPolarImg() const { return PolarImg.rows()!=0; } ; //!< Whether this feature has this kind of descriptor
126  bool hasDescriptorLogPolarImg() const { return LogPolarImg.rows()!=0; } ; //!< Whether this feature has this kind of descriptor
127  bool hasDescriptorMultiSIFT() const {
128  return (multiSIFTDescriptors.size() > 0 && multiSIFTDescriptors[0].size() > 0); //!< Whether this feature has this kind of descriptor
129  }
130  }
131  descriptors;
132 
133  /** Return the first found descriptor, as a matrix.
134  * \return false on error, i.e. there is no valid descriptor.
135  */
136  bool getFirstDescriptorAsMatrix(mrpt::math::CMatrixFloat &desc) const;
137 
138  /** Computes the normalized cross-correlation between the patches of this and another feature (normalized in the range [0,1], such as 0=best, 1=worst).
139  * \note If this or the other features does not have patches or they are of different sizes, an exception will be raised.
140  * \sa descriptorDistanceTo
141  */
142  float patchCorrelationTo( const CFeature &oFeature) const;
143 
144  /** Computes the Euclidean Distance between this feature's and other feature's descriptors, using the given descriptor or the first present one.
145  * \note If descriptorToUse is not descAny and that descriptor is not present in one of the features, an exception will be raised.
146  * \sa patchCorrelationTo
147  */
148  float descriptorDistanceTo( const CFeature &oFeature, TDescriptorType descriptorToUse = descAny, bool normalize_distances = true ) const;
149 
150  /** Computes the Euclidean Distance between "this" and the "other" descriptors */
151  float descriptorSIFTDistanceTo( const CFeature &oFeature, bool normalize_distances = true ) const;
152 
153  /** Computes the Euclidean Distance between "this" and the "other" descriptors */
154  float descriptorSURFDistanceTo( const CFeature &oFeature, bool normalize_distances = true ) const;
155 
156  /** Computes the Euclidean Distance between "this" and the "other" descriptors */
157  float descriptorSpinImgDistanceTo( const CFeature &oFeature, bool normalize_distances = true ) const;
158 
159  /** Returns the minimum Euclidean Distance between "this" and the "other" polar image descriptor, for the best shift in orientation.
160  * \param oFeature The other feature to compare with.
161  * \param minDistAngle The placeholder for the angle at which the smallest distance is found.
162  * \return The distance for the best orientation (minimum distance).
163  */
164  float descriptorPolarImgDistanceTo(
165  const CFeature &oFeature,
166  float &minDistAngle,
167  bool normalize_distances = true ) const;
168 
169  /** Returns the minimum Euclidean Distance between "this" and the "other" log-polar image descriptor, for the best shift in orientation.
170  * \param oFeature The other feature to compare with.
171  * \param minDistAngle The placeholder for the angle at which the smallest distance is found.
172  * \return The distance for the best orientation (minimum distance).
173  */
174  float descriptorLogPolarImgDistanceTo(
175  const CFeature &oFeature,
176  float &minDistAngle,
177  bool normalize_distances = true ) const;
178 
179  /** Save the feature to a text file in this format:
180  * "%% Dump of mrpt::vision::CFeatureList. Each line format is:\n"
181  * "%% ID TYPE X Y ORIENTATION SCALE TRACK_STATUS RESPONSE HAS_SIFT [SIFT] HAS_SURF [SURF] HAS_MULTI [MULTI]_i"
182  * "%% |---------------------- feature ------------------| |---------------------- descriptors ------------------------|"
183  * "%% with:\n"
184  * "%% TYPE : The used detector: 0:KLT, 1: Harris, 2: BCD, 3: SIFT, 4: SURF, 5: Beacon, 6: FAST\n"
185  * "%% HAS_* : 1 if a descriptor of that type is associated to the feature."
186  * "%% SIFT : Present if HAS_SIFT=1: N DESC_0 ... DESC_N-1"
187  * "%% SURF : Present if HAS_SURF=1: N DESC_0 ... DESC_N-1"
188  * "%% MULTI : Present if HAS_MULTI=1: SCALE ORI N DESC_0 ... DESC_N-1"
189  * "%%-------------------------------------------------------------------------------------------\n");
190  */
191  void saveToTextFile( const std::string &filename, bool APPEND = false );
192 
193  /** Get the type of the feature
194  */
195  TFeatureType get_type() const { return type; }
196 
197  /** Dump feature information into a text stream */
198  void dumpToTextStream( mrpt::utils::CStream &out) const;
199 
200  void dumpToConsole() const;
201 
202  /** Constructor
203  */
204  CFeature();
205 
206  /** Virtual destructor */
207  virtual ~CFeature() {}
208 
209 
210  protected:
211 
212  /** Internal function used by "descriptorLogPolarImgDistanceTo" and "descriptorPolarImgDistanceTo"
213  */
214  static float internal_distanceBetweenPolarImages(
215  const mrpt::math::CMatrix &desc1,
216  const mrpt::math::CMatrix &desc2,
217  float &minDistAngle,
218  bool normalize_distances,
219  bool dont_shift_angle );
220 
221  }; // end of class
222 
223 
224  /****************************************************
225  Class CFEATURELIST
226  *****************************************************/
227  /** A list of visual features, to be used as output by detectors, as input/output by trackers, etc.
228  */
230  {
231  protected:
232  typedef std::vector<CFeaturePtr> TInternalFeatList;
233 
234  TInternalFeatList m_feats; //!< The actual container with the list of features
235 
236  public:
237  /** The type of the first feature in the list */
238  inline TFeatureType get_type() const { return empty() ? featNotDefined : (*begin())->get_type(); }
239 
240  /** Save feature list to a text file */
241  void saveToTextFile( const std::string &fileName, bool APPEND = false );
242 
243  /** Save feature list to a text file */
244  void loadFromTextFile( const std::string &fileName );
245 
246  /** Copies the content of another CFeatureList inside this one. The inner features are also copied. */
247  void copyListFrom( const CFeatureList &otherList );
248 
249  /** Get the maximum ID into the list */
250  TFeatureID getMaxID() const;
251 
252  /** Get a reference to a Feature from its ID */
253  CFeaturePtr getByID( const TFeatureID &ID ) const;
254  CFeaturePtr getByID( const TFeatureID &ID, int &out_idx ) const;
255 
256  /** Get a vector of references to a subset of features from their IDs */
257  void getByMultiIDs( const vector<TFeatureID> &IDs, vector<CFeaturePtr> &out, vector<int> &outIndex ) const;
258 
259  /** Get a reference to the nearest feature to the a given 2D point (version returning distance to closest feature in "max_dist")
260  * \param x [IN] The query point x-coordinate
261  * \param y [IN] The query point y-coordinate
262  * \param max_dist [IN/OUT] At input: The maximum distance to search for. At output: The actual distance to the feature.
263  * \return A reference to the found feature, or a NULL smart pointer if none found.
264  * \note See also all the available KD-tree search methods, listed in mrpt::math::KDTreeCapable
265  */
266  CFeaturePtr nearest( const float x, const float y, double &max_dist ) const;
267 
268  /** Constructor */
269  CFeatureList();
270 
271  /** Virtual destructor */
272  virtual ~CFeatureList();
273 
274  /** Call this when the list of features has been modified so the KD-tree is marked as outdated. */
275  inline void mark_kdtree_as_outdated() const { kdtree_mark_as_outdated(); }
276 
277  /** @name Method and datatypes to emulate a STL container
278  @{ */
281 
282  typedef TInternalFeatList::reverse_iterator reverse_iterator;
283  typedef TInternalFeatList::const_reverse_iterator const_reverse_iterator;
284 
285  inline iterator begin() { return m_feats.begin(); }
286  inline iterator end() { return m_feats.end(); }
287  inline const_iterator begin() const { return m_feats.begin(); }
288  inline const_iterator end() const { return m_feats.end(); }
289 
290  inline reverse_iterator rbegin() { return m_feats.rbegin(); }
291  inline reverse_iterator rend() { return m_feats.rend(); }
292  inline const_reverse_iterator rbegin() const { return m_feats.rbegin(); }
293  inline const_reverse_iterator rend() const { return m_feats.rend(); }
294 
295  inline iterator erase(const iterator it) { mark_kdtree_as_outdated(); return m_feats.erase(it); }
296 
297  inline bool empty() const { return m_feats.empty(); }
298  inline size_t size() const { return m_feats.size(); }
299 
300  inline void clear() { m_feats.clear(); mark_kdtree_as_outdated(); }
301  inline void resize(size_t N) { m_feats.resize(N); mark_kdtree_as_outdated(); }
302 
303  inline void push_back(const CFeaturePtr &f) { mark_kdtree_as_outdated(); m_feats.push_back(f); }
304 
305  inline CFeaturePtr & operator [](const unsigned int index) { return m_feats[index]; }
306  inline const CFeaturePtr & operator [](const unsigned int index) const { return m_feats[index]; }
307 
308  /** @} */
309 
310 
311  /** @name Methods that MUST be implemented by children classes of KDTreeCapable
312  @{ */
313 
314  /// Must return the number of data points
315  inline size_t kdtree_get_point_count() const { return this->size(); }
316 
317  /// Returns the dim'th component of the idx'th point in the class:
318  inline float kdtree_get_pt(const size_t idx, int dim) const {
319  ASSERTDEB_(dim==0 || dim==1)
320  if (dim==0) return m_feats[idx]->x;
321  else return m_feats[idx]->y;
322  }
323 
324  /// Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class:
325  inline float kdtree_distance(const float *p1, const size_t idx_p2,size_t size) const
326  {
327  ASSERTDEB_(size==2)
328 
329  const float d0 = p1[0] - m_feats[idx_p2]->x;
330  const float d1 = p1[1] - m_feats[idx_p2]->y;
331  return d0*d0+d1*d1;
332  }
333 
334  // Optional bounding-box computation: return false to default to a standard bbox computation loop.
335  // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again.
336  // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)
337  template <typename BBOX>
338  bool kdtree_get_bbox(BBOX &bb) const { return false; }
339 
340  /** @} */
341 
342 
343  /** @name getFeature*() methods for template-based access to feature list
344  @{ */
345  inline float getFeatureX(size_t i) const { return m_feats[i]->x; }
346  inline float getFeatureY(size_t i) const { return m_feats[i]->y; }
347  inline TFeatureID getFeatureID(size_t i) const { return m_feats[i]->ID; }
348  inline float getFeatureResponse(size_t i) const { return m_feats[i]->response; }
349  inline bool isPointFeature(size_t i) const { return m_feats[i]->isPointFeature(); }
350  inline float getScale(size_t i) const { return m_feats[i]->scale; }
351  inline TFeatureTrackStatus getTrackStatus(size_t i) { return m_feats[i]->track_status; }
352 
353  inline void setFeatureX(size_t i,float x) { m_feats[i]->x=x; }
354  inline void setFeatureXf(size_t i,float x) { m_feats[i]->x=x; }
355  inline void setFeatureY(size_t i,float y) { m_feats[i]->y=y; }
356  inline void setFeatureYf(size_t i,float y) { m_feats[i]->y=y; }
357 
358  inline void setFeatureID(size_t i,TFeatureID id) { m_feats[i]->ID=id; }
359  inline void setFeatureResponse(size_t i,float r) { m_feats[i]->response=r; }
360  inline void setScale(size_t i,float s) { m_feats[i]->scale=s; }
361  inline void setTrackStatus(size_t i,TFeatureTrackStatus s) { m_feats[i]->track_status=s; }
362 
363  inline void mark_as_outdated() const { kdtree_mark_as_outdated(); }
364 
365  /** @} */
366 
367 
368  }; // end of class
369 
370  /****************************************************
371  Class CMATCHEDFEATURELIST
372  *****************************************************/
373  /** A list of features
374  */
375  class VISION_IMPEXP CMatchedFeatureList : public std::deque< std::pair<CFeaturePtr,CFeaturePtr> >
376  {
377  public:
378  /** The type of the first feature in the list */
379  inline TFeatureType get_type() const { return empty() ? featNotDefined : (begin()->first)->get_type(); }
380 
381  /** Save list of matched features to a text file */
382  void saveToTextFile(const std::string &fileName);
383 
384  /** Returns the matching features as two separate CFeatureLists */
385  void getBothFeatureLists( CFeatureList &list1, CFeatureList &list2 );
386 
387  /** Returns a smart pointer to the feature with the provided ID or a empty one if not found */
388  CFeaturePtr getByID( const TFeatureID & ID, const TListIdx &idx );
389 
390  /** Returns the maximum ID of the features in the list. If the max ID has been already set up, this method just returns it.
391  Otherwise, this method finds, stores and returns it.*/
392  void getMaxID( const TListIdx &idx, TFeatureID & firstListID, TFeatureID & secondListID );
393 
394  /** Updates the value of the maximum ID of the features in the matched list, i.e. it explicitly searches for the max ID and updates the member variables. */
395  void updateMaxID( const TListIdx &idx );
396 
397  /** Explicitly set the max IDs values to certain values */
398  inline void setLeftMaxID( const TFeatureID &leftID ){ m_leftMaxID = leftID; }
399  inline void setRightMaxID( const TFeatureID &rightID ){ m_rightMaxID = rightID; }
400  inline void setMaxIDs( const TFeatureID &leftID, const TFeatureID &rightID )
401  {
402  setLeftMaxID(leftID);
403  setRightMaxID(rightID);
404  };
405 
406  /** Constructor */
408 
409  /** Virtual destructor */
410  virtual ~CMatchedFeatureList();
411  protected:
412  TFeatureID m_leftMaxID, m_rightMaxID;
413  }; // end of class
414 
415 
416  /** @} */ // End of add to module: mrptvision_features
417 
418  } // end of namespace
419 
420 
421  namespace utils
422  {
423  using namespace ::mrpt::vision;
424  // Specialization must occur in the same namespace
426  }
427 } // end of namespace
428 
429 #endif
430 



Page generated by Doxygen 1.8.3 for MRPT 0.9.6 SVN: at Fri Feb 15 22:05:02 EST 2013