在前两篇文章中,楼主已经向大家展示了Ubuntu16.04+OpenCV-3.1.0(带contrib模块)的安装编译方法。接下来,我们开始进入正题,特征点提取与匹配的实践操作。本篇文章中,我将着重介绍SIFT这种特征点以及做一个简单的特征点提取实践。
1.什么是特征点?
首先我们来介绍一下什么是特征点,从字面的意思上来解释就是能反应事物特征的点,在事物的自然特征点中,多为角点、边上的点、以及面点。但是自然特征点不具有尺度不变性,什么是尺度不变性呢?通俗的将就是特征点随着尺度的变化具有一定的稳定性。例如一个角点,在远处看是一个角点,当我们走进看时,可能就不能判断它是一个角点。为了解决这个问题,牛人们人工的设计了一些特征点:如SIFT、SURF、ORB等
这些人工设计的特征点一般具有以下性质:
(1)可重复性:即相同的特征可在不同的图像中找到;
(2)可区别性:即同一帧图像的不同特征有不同的表示;
(3)高效性:即特征点的数量远小于像素点的数量;
(4)本地性:即特征点仅与一小块区域相关。
2.SIFT特征点
SIFT(Scale Invariant Feature Transform)又称尺度不变特征变换。SIFT特征是目前最稳定的特征点,对尺度、旋转等都有很好的鲁棒性。对于噪声、仿射变换等也有保持较好的稳定性。
SIFT特征的提取主要包括一下四部:
(1)尺度空间极值检测;
(2)特征点的定位;
(3)为特征点赋予方向信息;
(4)描述子的生成。
对于SIFT特征点的关键点,我们事实上是通过构建图像金子塔来为特征点加上尺度信息的。所谓的图像金字塔就是对一幅图像进行降采样,在不同分辨率下提取图像的特征点。说的直白一点就是类似于我们人眼看物体,在一定情况下距离越近看到的事物越模糊,图像金字塔就是这样工作的,金字塔顶端的图像分辨率较低。另外有一种高斯金字塔,高斯金字塔是通过高斯函数对图像进行不同程度的模糊处理得到的,那么什么是高斯函数呢?他长成这个样子(编辑公式太麻烦,原谅我直接截图):
下图为构建的高斯金字塔:
在2002年,一名外国科学家(名字记不得了)发现尺度归一化的高斯拉普拉斯函数极大值和极小值产生的特征点比其他算法产生的特征点更加稳定,而高斯差分函数与高斯拉普拉斯函非常相似,因此,大牛们又建立了高斯差分金字塔.高斯差分金字塔的产生可由高斯金字塔相邻两层直接相减获得.如下图所示:
这样,我们在构建好的高斯差分金子塔上检测像素点的极大值和极小值,就完成了对图像关键点的定位.
接下来为了使提取的特征点具有旋转不变性,我们要对特征点添加方向信息.如何操作呢?
我们使用关键点领域的像素值的梯度来代表关键点的方向.梯度的方向和模用如下公式计算:
这样在关键点的邻域像素内我们就可以通过梯度直方图的最大值来给关键点赋予方向信息.(就是对同一的梯度方向加权累加,得到的最大值就是关键点的主方向)如下图所示:
为了实现特征点的可重复性,我们需要对特征点使用一种描述来判断两幅图像中的特征点是否为同一个特征点.也就是描述子的生成.SIFT的描述子是用邻域像素的梯度进行描述的.
这样我们讲述了SIFT特征的原理,下面进入实践部分.你需要配置的环境为ubuntu16.04+opencv-3.1.0(带contrib模块)
代码部分:
//声明关键点
vector<KeyPoint> keypoints_1;
//定义mat型变量 descriptors_1
Mat descriptors_1;
//计时器函数
clock_t time_stt=clock();
cout<<"< Extracting keypoints from images using SITF..."<<endl;
//SIFT类的声明
Ptr<Feature2D> f2d = xfeatures2d::SIFT::create();
//将关键点、描述子存在f2d内
f2d->detect(image, keypoints_1);
f2d->compute(image, keypoints_1, descriptors_1);
//输出关键点个数和计算挂关键点作用时间
cout<<"image has"<<keypoints_1.size()<<"points"<<endl;
cout<<"time use in SITF is"<<1000 * (clock() - time_stt)/(double)CLOCKS_PER_SEC << "ms" << endl;
这里为部分代码,功能是输入一张图片,提取图片特征点并统计特征点个数, 统计提取时间.效果如下:SIFT特征点讲解到这里,本文代码均为原创,转发请标明出处,如要完整代码可以评论留邮箱.