SIFT特征点相对于ORB计算速度较慢,在没有GPU加速情况下,无法满足视觉里程计的实时性要求,或者无法运行在手机平台上,但是效果更好,精度更高。在应用时可以择优选取,了解其本质原理的动机是为了自己使用时,可以对其进行修改,针对自己的应用场景优化算法。

有足够的时间,可以去看D. Lowe的论文,理解起来更透彻.

1. 用高斯核构建尺度空间

对于构建的高斯金字塔,金字塔每层多张图像合称为一组(Octave),每组有多张(也叫层Interval)图像。通常高斯金字塔最底层为原始图像第0组,octave之间为降采样过程,对应OpenCV里的函数为PryDown()。注意这里降采样PryDown在直观上是金字塔向上走,要注意区分。

金字塔的第i组octave通过对第i-1组降采样获得(通常降采样的比例为2,也就是高斯模糊后去掉偶数行/列像素)。在每一组octave中还需要使用高斯核σ创建连续的尺度空间图像: σ, kσ, k2σ,..., kn-1σ,其中,k=21/s,s为每一组octave中再分的尺度层数。构建连续尺度空间的目的是为了提取特征点(角点)时,该特征点不仅在二维图像空间中是梯度极值点,还需要在第三维的尺度空间也是极值点。

当然,检测角点并不是直接在高斯卷积构建的尺度空间中,而是DoG(Difference of Gaussian)高斯差分尺度空间中,因此,为了保证DOG高斯差分尺度空间变化的连续性(是高斯卷积空间相邻尺度的差),需要在每一层octave的高斯卷积尺度首尾两边多创建一个尺度。

这里注意理解连续性,不是微积分里面的连续性,指的是尺度空间连续,(σ, kσ, k2σ,..., ks-1σ) ,(2σ, 2kσ, 2k2σ,..., 2ks-1σ) 。从这里可以看出,尺度空间主要由σ主导.

2. 在DoG尺度空间中检测极值点

  虽然在高斯拉普拉斯LoG尺度空间中检测极值点是最精确的,但是由于计算量比较大,通常使用DoG尺度空间对其进行近似,在DoG尺度空间中进行局部最值搜索。有关LoG可以参考http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html.LoG也就是将拉普拉斯算子作用于高斯核函数后形成的新的核函数,拉普拉斯算子的作用是求二阶偏导,对噪点响应较敏感,因此需要先用高斯核对图像进行平滑.

  由于DoG尺度空间是离散的,我们只能通过比较DoG空间中某个点周围26个点来获取一个点是否可以作为极值(和ORB一样,这里可以选较少的几个先比较剔除).

        

但是为了进一步获得精确的亚像素级别特征点位置,需要将DoG函数D(x,y,σ)在像素极值点附近二阶展开,对亚像素极值求偏导后=0求解.

    

    

第二式带入第一式后可以得到亚像素极值点对应的DoG函数值,也就是对比度contrast:

    

  在检测到DoG尺度空间中的极值点(extremum)后,使用两个阈值来剔除质量不高(unstable)的点,contrastThreshold以及edgeThreshold.首先在DoG尺度空间中在potential的极值点附近二阶泰勒展开,寻找更精确的极值点坐标,其中,contrastThreshold是为了剔除对比度不高的极值点,edgeThreshold是为了剔除边缘点,因为边缘点也满足极值点的条件,但是不是需要的角点.

剔除对比度不高(不稳定)的点,|D(x)| < 0.03,这里假设DoG函数取值范围[0, 1].

剔除边缘点借鉴了Harris Corner的检测方法,计算特征点邻域的Hessian矩阵。

    

一次求导物理意义是变化率/梯度,二次求导物理意义是曲率,因此Hessian矩阵更能体现一个边缘的特征程度。

该Hessian矩阵的特征值代表了边缘特征的主曲率。两个特征值之间的比例体现了邻域两个垂直方向的曲率差别,这里去掉比例较大(横跨边缘和沿着边缘方向的曲率差别较大,>10)的点。注意这里不用特征值分解,而是用矩阵迹和行列式的性质,得到两个特征值比例就行.

3. 计算特征点方向

在检测到的特征点一个圆形邻域像素集合上计算各自的梯度幅值和梯度方向:

     

将360度方向划分为方向直方图中的36个bins,获取直方图的peak,作为特征点的方向。如果存在大于80%*peak幅值的方向,则在同一个尺度特征点(x,y,σ)上新建一个方向不同的特征点,有多少个新建多少个特征点.论文中说,相同位置的不会超过15%, 但是可以显著增强匹配的稳定性.注意这里的邻域是有区分度的,距离特征点近的像素在计算直方图时权重较大,使用高斯分布加权处理。

获得关键点主方向后,每个关键点有三个信息(x,y,σ,θ):位置、尺度、方向。

4. 计算128维描述子

在对邻域像素点采样前,要旋转xy坐标系和关键点的方向对齐,使得特征点具备方向不变的特征(旋转相机后,特征点描述子不变)。

将旋转后区域划分为4×4=16个子区域(每个区域间隔为mσ像元),在每个子区域内计算8个方向的梯度直方图,绘制每个方向梯度方向的累加值,形成一个种子点。
与求主方向不同的是,此时,每个子区域梯度方向直方图将0°~360°划分为8个方向区间,每个区间为45°。即每个种子点有8个方向区间的梯度强度信息。由于存在d×d,即4×4个子区域,所以最终共有4×4×8=128个数据,形成128维SIFT特征矢量。

计算128维空间中描述子的距离,SIFT的实现中计算的是欧氏距离.

练习:

OpenCV中提供的goodFeatureToTrack()可以使用Harris和Shi-Tomasi角点检测算法对图像进行角点提取,注意没有构建尺寸空间,且没有提供描述子计算,是最简单的角点提取算法,但是通过对其参数的调整,可以了解一些实现特点:

#include "common.h"
#include <opencv2/nonfree/features2d.hpp> using namespace std;
using namespace cv; Mat origin, img;
vector<Point2f> keyPoints;
string title("FeatureDetector");
int maxCorners();
int qualityLevel();
int minDistance();
int blockSize();
int useHarrisDetector();
int k();
int method(); void detectCorner(int, void*); int main(){
origin = imread("/home/shang/dataset/opencv/building.jpg",CV_LOAD_IMAGE_COLOR);
if(!origin.data){
cerr << "No data!"<< endl;
return -;
}
cvtColor(origin, img, CV_BGR2GRAY);
namedWindow(title);
createTrackbar("maxCorners", title, &maxCorners, , detectCorner);
createTrackbar("qualityLevel (%)", title, &qualityLevel, , detectCorner);
createTrackbar("minDistance", title, &minDistance, , detectCorner);
createTrackbar("blockSize", title, &blockSize, , detectCorner);
createTrackbar("useHarrisDetector", title, &useHarrisDetector, , detectCorner);
createTrackbar("k when in HarrisDetector", title, &k, , detectCorner);
createTrackbar("Method", title, &method, , detectCorner);
detectCorner(,);
imshow(title, img); while(true){
if(waitKey()==)
break;
}
} void detectCorner(int, void*){
Mat result ;
img.copyTo(result);
switch (method){
case :
if(qualityLevel==) {
qualityLevel = ;
setTrackbarPos("qualityLevel (%)", title, );
}
if(blockSize==) {
blockSize = ;
setTrackbarPos("blockSize", title, );
}
goodFeaturesToTrack(result,
keyPoints,
maxCorners,
qualityLevel/100.0,
minDistance,
noArray(),
blockSize,
useHarrisDetector,
k/100.0
); cvtColor(result, result, CV_GRAY2RGB);
for(vector<Point2f>::const_iterator it=keyPoints.begin(); it!=keyPoints.end(); it++){
circle(result, *it, , Scalar(,,),);
}
imshow(title, result);
break;
case :
SiftFeatureDetector detector();
vector<KeyPoint> keyPoints;
detector.detect(result, keyPoints);
cvtColor(result, result, CV_GRAY2RGB);
for(vector<KeyPoint>::const_iterator it=keyPoints.begin(); it!=keyPoints.end(); it++){
rectangle(result, Rect(it->pt.x-,it->pt.y-,,), Scalar(,,),);
}
imshow(title, result);
break;
} }

参考:

SIFT特征提取分析

【OpenCV】SIFT原理与源码分析

SIFT 特征点提取算法的更多相关文章

  1. opencv学习之路(33)、SIFT特征点提取(一)

    一.简介 二.OpenCV中的SIFT算法接口 #include "opencv2/opencv.hpp" #include <opencv2/nonfree/nonfree ...

  2. 基于SIFT特征的全景图像拼接

    基于SIFT特征的全景图像拼接 分类: image Machine learning2013-07-05 13:33 2554人阅读 评论(3) 收藏 举报 基于SIFT特征的全景图像拼接 分类: 计 ...

  3. SIFT特征原理简析(HELU版)

    SIFT(Scale-Invariant Feature Transform)是一种具有尺度不变性和光照不变性的特征描述子,也同时是一套特征提取的理论,首次由D. G. Lowe于2004年以< ...

  4. Sift算子特征点提取、描述及匹配全流程解析

    Sift之前的江湖 在Sift横空出世之前,特征点检测与匹配江湖上占据霸主地位的是角点检测家族.先来探究一下角点家族不为人知的恩怨情仇. 角点家族的族长是Moravec在1977年提出的Moravec ...

  5. opencv java api提取图片sift特征

    opencv在2.4.4版本以后添加了对java的最新支持,可以利用java api了.下面就是我利用opencv的java api 提取图片的sift特征. import org.opencv.co ...

  6. OpenCV特征点提取----Fast特征

    1.FAST(featuresfrom accelerated segment test)算法 http://blog.csdn.net/yang_xian521/article/details/74 ...

  7. opencv学习之路(35)、SURF特征点提取与匹配(三)

    一.简介 二.opencv中的SURF算法接口 三.特征点匹配方法 四.代码 1.特征点提取 #include "opencv2/opencv.hpp" #include < ...

  8. FAST特征点检测算法

    一 原始方法 简介 在局部特征点检测快速发展的时候,人们对于特征的认识也越来越深入,近几年来许多学者提出了许许多多的特征检测算法及其改进算法,在众多的特征提取算法中,不乏涌现出佼佼者. 从最早期的Mo ...

  9. 特征点检测算法——FAST角点

    上面的算法如SIFT.SURF提取到的特征也是非常优秀(有较强的不变性),但是时间消耗依然很大,而在一个系统中,特征提取仅仅是一部分,还要进行诸如配准.提纯.融合等后续算法.这使得实时性不好,降系了统 ...

随机推荐

  1. Intellij IDEA 代码中类非全路径显示

  2. luogu P1642 规划

    嘟嘟嘟 看到最后让求一个比值,应该得往01规划上去想.令x = ∑v[i] / ∑c[i],则x * ∑c[i] = ∑v[i], ∑(v[i] - x * c[i]) = 0. 于是可以二分x(注意 ...

  3. JavaScript小游戏--2048(PC端)

    1.初始化棋局 $(document).ready(function() { prepare_for_mobile(); //适配移动端 new_game(); }); 2.开始新游戏 functio ...

  4. Kali-linux攻击WordPress和其他应用程序

    今天越来越多的企业利用SAAS(Software as a Service)工具应用在他们的业务中.例如,他们经常使用WordPress作为他们网站的内容管理系统,或者在局域网中使用Drupal框架. ...

  5. Jupyter Notebook 设置黑色背景主题、字体大小、代码自动补全

    1.背景主题.字体大小设置 安装Jupyter主题: pip install jupyterthemes 然后,更新Jupyter主题: pip install --upgrade jupyterth ...

  6. java中数据类型的范围

    前言:最近:本菜鸡在准备pat,可以每次遇到数据类型的时候都得去查找范围,因此本着学习的目的,来总结一下java中的数据类型. 因此我用mindManager做了一个思维图

  7. IP Addressing

    IP Addressing(处理) Each host on Internet has unique 32 bit IP address Each address has two parts: net ...

  8. 陈正冲老师讲c语言之内存的申请malloc() 和释放free()

    1.如何使用 malloc 函数 不要莫名其妙,其实上面这段小小的对话,就是malloc的使用过程.malloc是一个函数,专门用来从堆上分配内存.使用malloc函数需要几个要求: 内存分配给谁?分 ...

  9. Objective-C中的@dynamic与@synthesize的区别

    Objective-C中的@dynamic 转自:http://blog.csdn.net/haishu_zheng/article/details/12873151 一.@dynamic与@synt ...

  10. 安全清理Xcode 缓存垃圾

    安全清理Xcode缓存垃圾方法: 经验证,Xcode缓存垃圾存储在~/Library/Developer/Xcode/DerivedData/路径下,缓存和Xcode的版本有关(如同一台Mac安装2个 ...