opencv图像特征点的提取和匹配(一)
opencv中进行特征点的提取和匹配的思路一般是:提取特征点、生成特征点的描述子,然后进行匹配。opencv提供了一个三个类分别完成图像特征点的提取、描述子生成和特征点的匹配,三个类分别是:FeatureDetector,DescriptorExtractor,DescriptorMatcher。从这三个基类派生出了不同的类来实现不同的特征提取算法、描述及匹配。
首先是特征提取基类:FeatureDetector,实现二维图像特征的提取。这个类是派生于Algorithm类,这个类应该是封装了大量的算法。FeatureDetector的具体实现如下:
class CV_EXPORTS FeatureDetector
{
public:
virtual ~FeatureDetector();
void detect( const Mat& image, vector& keypoints,
const Mat& mask=Mat() ) const;
void detect( const vector& images,
vector >& keypoints,
const vector& masks=vector() ) const;
virtual void read(const FileNode&);
virtual void write(FileStorage&) const;
static Ptr create( const string& detectorType );
protected:
...
};
通过定义FeatureDetector对象,并调用静态成员函数create函数根据名字来实现多种特征检测方法,具体实现如下:
Ptr FeatureDetector::create(const string& detectorType)
支持的算子主要包括以下几种:
“FAST”—FastFeatureDetector;
"STAR"—StarFeatureDetector;
"SIFT"— SiftFeatureDetector;
"SURF"—SurfFeatureDetector;
"ORB" — OrbFeatureDetecotr;
"MSER"—MserFeatureDetector;
"GFTT"— GoodFeatureDetector;
"HARRIS"—GoodFeatureToTrackDetector;
"Dense" —DenseFeatureDetector;
"SimpleBlob"—SimpleBlobDectector;
还支持组合类型:特征检测算子的适配器名字("Grid"-GridAdaptedFeatureDetector,"Pyramid"-PyramidAdaptedFeatureDetector)+对应特征检测算子(上面支持的类型)的名字构成。比如:“GridFAST”、“PyramidSTAR”等。
从FeatureDetector类派生出了对应于不同检测算法的子类:FastFeatureDetector、MserFeatureDetector、StarFeatureDetector、SiftFeatureDetector、SurfFeatureDetector、OrbFeatureDetector、SimpleBlobDetector等。
头文件的处理:在opencv2.4.9中,如果要提取sift特征或者surf特征的话,应该添加头文件
class CV_EXPORTS_W SIFT : public Feature2D
{
public:
CV_WRAP explicit SIFT( int nfeatures=0, int nOctaveLayers=3,
double contrastThreshold=0.04, double edgeThreshold=10,
double sigma=1.6);
//! returns the descriptor size in floats (128)
CV_WRAP int descriptorSize() const;
//! returns the descriptor type
CV_WRAP int descriptorType() const;
//! finds the keypoints using SIFT algorithm
void operator()(InputArray img, InputArray mask,
vector& keypoints) const;
//! finds the keypoints and computes descriptors for them using SIFT algorithm.
//! Optionally it can compute descriptors for the user-provided keypoints
void operator()(InputArray img, InputArray mask,
vector& keypoints,
OutputArray descriptors,
bool useProvidedKeypoints=false) const;
AlgorithmInfo* info() const;
void buildGaussianPyramid( const Mat& base, vector& pyr, int nOctaves ) const;
void buildDoGPyramid( const vector& pyr, vector& dogpyr ) const;
void findScaleSpaceExtrema( const vector& gauss_pyr, const vector& dog_pyr,
vector& keypoints ) const;
protected:
...
};
typedef SIFT SiftFeatureDetector;
typedef SIFT SiftDescriptorExtractor;
可以看出SIFT类派生于feature2D类,而feature2D有派生于FeatureDetector类和DescriptorExtractor类;因此派生于feature2D类的类的对象既可以调用FeatureDetector的成员函数实现特征的提取,又可以调用DescroptorExtractor的成员函数来生成特征描述子。由SIFT类定义的后面两句(typedef...)也可以看出,通过SIFT类声明的对象拥有提取特征和生成特征描述子的双重功能。
注意:可能是由于opencv版本的原因,网上有些参考资料(包括opencv自带的用户手册)解释说:在提取SIFT特征和SURF特征时,需要添加
#include "opencv2/nonfree/features2d.hpp"
namespace cv
{
CV_EXPORTS_W bool initModule_nonfree();
}
我在opencv2.4.9中直接添加头文件
SURF类的应用和SIFT类一样;ORB特征检测算子也可以像SIFT类一样直接声明对象然后使用,因为也存在一个派生于feature2D类的ORB类。其他算子好像都不行,但存在对应的子类来单独实现特征的检测。
下面给出对图像进行SIFT特征检测和匹配的程序:
#include
#include
#include
#include
using namespace std;
using namespace cv;
int main(int argc,char* argv[])
{
Ptr siftMatcher = DescriptorMatcher::create("BruteForce");
SiftFeatureDetector siftDetector;
Mat img1 = imread("box.png");
Mat img2 = imread("box_in_scene.png");
vector keypoints1,keypoints2;
siftDetector.detect(img1,keypoints1);
siftDetector.detect(img2,keypoints2);
cout<<"Number of detected keypoints img1:"< matches;
siftMatcher->match(descriptor1,descriptor2,matches,Mat());
Mat imgmatches;
drawMatches(img1,
keypoints1,
img2,
keypoints2,
matches,
imgmatches,
Scalar::all(-1),
Scalar::all(-1),
vector(),
DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
imshow("Match Results:",imgmatches);
waitKey(0);
return 0;
}
匹配结果:
上面的结果是在opencv2.4.9+vs2010+win7中运行的。鉴于水平有限,难免有错误,希望指正,共同进步!!