开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天
1 概述
通过上一节SURF相关内容的讲解,我们已经对SURF算法有了一定的理解。SURF 算法为每个检测到的特征定义了位置和尺度,尺度值可用于定义围绕特征点的窗口大小。不论物体的尺度在窗口是什么样的,都将包含相同的视觉信息,这些信息用于表示特征点以使得它们与众不同。
在特征匹配中,特征描述子通常用于N维向量,在光照不变以及少许透视变形的情况下很理想。另外,优质的描述子可以通过简单的距离测量进行比较,比如欧氏距离。因此,它们在特征匹配算法中,用处是很大的。
在OpenCV 中,使用 SURF 进行特征点描述主要是 drawMatches 方法和 BruteForceMatcher类的运用,下面让我们一起来认识它们。
2 绘制匹配点:drawMatches()函数
drawMatches 用于绘制出相匹配的两个图像的关键点,它有以下两个版本的C++函数原型。
C++:
void drawMatches (
const Mat& img1,
constvector& keypoints1,
const Mat& img2,
constvector& keypoints2,
constvector& matches1to2,
Mat& outImg,
const Scalar&matchColor=Scalar::all(-1),
const Scalar&singlePointColor=Scalar::all(-1),
const vector&matchesMask=vector(),
intflags=DrawMatchesFlags::DEFAULT
)
C++:
void drawMatches (
const Mat& img1,
constvector& keypoints1,
const Mat& img2,
constvector& keypoints2,
const vector<vector>&matches1to2,
Mat& outImg,
const Scalar&matchColor=Scalar::all(-1),
const Scalar&singlePointColor=Scalar::al1(-1),
constvector<vector>&matchesMask=vector<vector>(),
intflags=DrawMatchesFlags::DEFAULT
)
除了第五个参数matcheslto2和第九个参数 matchesMask 有细微的差别以外,两个版本的基本上相同。下面统一讲解。
- 第一个参数,const Mat&类型的img1,第一幅源图像。
- 第二个参数,const vector<KeyPoint>&类型的keypoints1,根据第一幅源图 像得到的特征点,它是一个输出参数。
- 第三个参数,const Mat&类型的img2,第二幅源图像。
- 第四个参数,constvector<KeyPoint>&类型的keypoints2,根据第二幅源图 像得到的特征点,它是一个输出参数。
- 第五个参数,matcheslto2,第一幅图像到第二幅图像的匹配点,即表示每一个图1中的特征点都在图2中有一一对应的点、
- 第六个参数,Mat&类型的outImg,输出图像,其内容取决于第五个参数标识符falgs。
- 第七个参数,const Scalar&类型的matchColor,匹配的输出颜色,即线和关 键点的颜色。它有默认值Scalar::all(—1),表示颜色是随机生成的。
- 第八个参数,const Scalar&类型的singlePointColor,单一特征点的颜色,它 也表示随机生成颜色的默认值 Scalar::all(—1)。
- 第九个参数,matchesMask,确定哪些匹配是会绘制出来的掩膜,如果掩膜为空,表示所有匹配都进行绘制。
- 第十个参数,int类型的 flags,特征绘制的标识符,有默认值DrawMatchesFlags::DEFAULT。可以在如下这个DrawMatchesFlags 结构体 中选取值:
struct DrawMatchesFlags
{
enum
{
DEFAULT=0,//创建输出图像矩阵(使用Mat::create)。使用现存的输出图像绘制匹配对和特征点。且对每一个关键点,只绘制中间点
DRAW_OVER_OUTIMG=1,//不创建输出图像矩阵,而是在输出图像上绘制匹配对
NOT_DRAW_SINGLE_POINTS=2,//单点特征点不被绘制
DRAW_RICH_KEYPOINTS=4//对每一个关键点,绘制带大小和方向的关键点圆圈
};
};
3 BruteForceMatcher类源码分析
接下来,我们看看本节中会用到的 BruteForceMatcher 类的源码分析,BruteForceMatcher 类用于进行暴力匹配相关的操作。
在......\opencv\sources modules\legacy\includelopencv2\ legacy\legacy.hpp 路径下,可以找到 BruteForceMatcher类的定义。
template<class Distance>
class CV_EXPORTS BruteForceMatcher: publicBFMatcher
{
public:
BruteForceMatcher(Distance d =Distance())
: BFMatcher (Distance::normType,false)
{
(void)d;
}
virtual ~BruteForceMatcher(){}
};
其公共继承自BFMatcher类。
而BFMatcher类位于···\opencv\sources\modules\features2d\include\opencv2\features2d\features2d.hpp 路径之下,
我们一起看看其代码。
class CV_EXPORTS_W BFMatcher: publicDescriptorMatcher
{
//......
};
发现公共其继承自 DescriptorMatcher 类,再次进行溯源,在D:\Program Files(x86)\opencv\sources\modules\features2d\include\opencv2\features2d\features2d. hpp路径下找到DescriptorMatcher类的定义。
class CV_EXPORTS W DescriptorMatcher :public Algorithm
{
//
};
可以发现,DescriptorMatcher 类和之前我们讲到 FeatureDetector类和 DescriptorExtractor类一样,都是继承自它们“德高望重的祖先”Algorithm基类的。
而用BruteForceMatcher类时用到最多的match方法,是它从DescriptorMatcher 类那里继承而来。定义如下。
//为各种描述符找到一个最佳的匹配(若掩膜为空)
CV_WRAP void match( const Mat& queryDescriptors, const Mat&trainDescriptors,
CV_OUTvector<DMatch>&matches,const Mat& mask=Mat())const;