SIFT算法原理详解及代码实现(笔记)

article/2025/10/26 15:30:30

一、SIFT算法概述:
SIFT(Scale Invariant Feature Transform)全称尺度不变特征变换,SIFT算子是把图像中检测到的特征点用一个128维的特征向量进行描述,因此一幅图像经过SIFT算法后表示为一个128维的特征向量集,该特征向量集具有对图像缩放,平移,旋转不变的特征,对于光照、仿射和投影变换也有一定的不变性,是一种非常优秀的局部特征描述算法。
SIFT算法步骤分为:
(1).尺度空间极点检测
(2).关键点精确定位
(3).确定关键点方向
(4).生成特征向量
二、尺度空间极点检测
2.1 尺度空间
特征点的检测就是寻找特征点的位置和尺度,需要位置的原因显而易见,而需要尺度的原因则是因为真实世界中的物体只有在一定尺度下才有意义。我们寻找的特征点就是要找到在连续的尺度空间下位置不发生改变的点。

构建尺度空间的目的就是找到在尺度变化中具有不变性的位置,可以使用连续的尺度变化,即在尺度空间中所有可能的尺度变化中找到稳定的特征点,通过这种方式找到的极点可以保证在图像缩放和旋转变化中具有不变性。

经过前人证明,尺度空间内核是高斯函数。因此假设I(x,y)是原始图像,G(x,y,σ)是尺度空间可变的高斯函数,则一个图像的尺度空间可以定义为:在这里插入图片描述
其中,∗表示的是卷积运算,σ表示尺度空间的大小,σ越大则表示越模糊,表示图像的概貌,σ越小则表示越清晰,表示图像的细节。高斯函数G(x,y,σ)定义为:
在这里插入图片描述
经过一系列的尺度空间变换和二倍的下采样,最终得到高斯金字塔。
需要注意的是公式1中的图像I(x,y)具有无限的分辨率,也就是说他的尺度σ=0,即I(x,y)=L(x,y,0)。也就是说公式1得到的尺度空间图像L(x,y,σ)是由尺度尺度空间为0的图像L(x,y,0)生成的,但是现实生活中是不存在尺度空间为0,即具有无限分辨率的图像的。在Lowe的论文中,他们给定原图一个很小的尺度空间,为0.5。因此由一个小尺度空间图像L(x,y,σ1)生成一个大的尺度空间图像L(x,y,σ2)的过程为:
在这里插入图片描述在这里插入图片描述
2.2 高斯差分(DOG)
高斯差分可以在尺度空间中找到稳定不变的极值点,高斯差分(DOG)函数D(x,y,σ)定义为:
在这里插入图片描述
其中kσ和σ是连续的两个图像的平滑尺度,所得到的差分图像再高斯差分金字塔中。

为何选择高斯差分函数:

  1. 计算简单,因为L(x,y,σ)是一定需要计算的,而D(x,y,σ)只需要执行减法。
  2. 高斯拉普拉斯算子LoG(Laplacian of Gaussian),即图像的二阶导数,能够在不同的尺度下检测到图像的斑点特征,从而检测到图像中尺度变化下的位置不动点,但是LoG的运算效率不高。而DoG是LoG的近似。DoG和LoG的关系如下述所示:
    在这里插入图片描述
    故而:
    在这里插入图片描述
    而σ2∇2G正是尺度归一化算子的表达形式。在所有的尺度中k−1是一个常数,当k趋近于1的时候误差趋近于0,但实际上这种误差对于极值的位置检测并没有什么影响
  3. 通过前人的实验证明LoG提取的特征稳定性最强。

2.3 高斯金字塔与高斯差分金字塔
高斯金字塔和高斯差分金字塔如下图所示:
在这里插入图片描述
这里的几个参数定义如下:
4. 金字塔的组数(number of octaves):大多数情况下为4,但是实际上这个值与图像的大小有关,我在网上查到的资料大多数为⌊log2(min(M,N))⌋−3或者⌊log2(min(M,N))⌋−2,具体实现看效果确定吧。
5. 每层的组数:S1=s+3这里s为极值检测需要的层数,一般取3到5。
6. 参数: 在这里插入图片描述,σ0=1.6

高斯金字塔的生成过程:
设我们输入的图像的尺度为0.5(Lowe论文中设定),由该图像进行高斯模糊得到第0组的第0层图像作为基准图像,设它的尺度为σ0,即Lowe论文中的1.6,我们称σ0为基准层尺度,由第0层生成第1层图像的尺度为kσ0,第1层生成第2层的尺度为k2σ0,依次类推。 那么第0组中的图像的尺度为:
σ=krσ0,r=0,1,…,s+2
当第0组构建完以后,再构建第1组,第1组中的第0层图像是根据第0组的倒数第三张图像进行隔点采样得到的。由上面公式我们可以知道,第0组的倒数第三层的尺度为在这里插入图片描述,而在这里插入图片描述因此其尺度为2σ0,所以第1组的第0张图像的尺度依然为2σ0。
但是第1组中的图像是第0组中的图像经过隔点采样后得到的,因此相对于输入图像分辨率来说,其尺度为2σ0,而对于第1组中的图像分辨率来说,其尺度为σ0。因此我们称σ0为基准层尺度。
上述总结规律如下:
第o组中的第r个图像相对于输入图像的尺度为:
在这里插入图片描述
而DoG金字塔的生成过程就比较简单了,就是由高斯金字塔相邻的两层相减得到DoG金字塔中的一层,然后依次得到。由高斯金字塔中每组有s+3层,所以高斯差分金字塔中每组有s+2层。

金字塔中每一组(octave)中的每层(scale)的平滑尺度都不同,下一组的第一层都是由上一层的倒数第三张的图像隔点降采样得到的。

这样做的目的是使DoG满足尺度连续性。

2.4 极值点的选定
如上图的最右方所示,只有当前点与其周围24个点值相比,如果是最大值或者最小值则该点为极值点,否则不是。这种比较计算量比较小,因为大多数的点在比较的前几步就已经被pass掉了 。

三、特征点的精确定位
计算机中存储的图像数据是离散的,而我们之前找到的极值点也就是离散空间中的极值点,但是离散空间中的极值点并不是真实的连续空间中的极值点。所以需要对DoG空间进行拟合处理,以找到极值点的精确位置和尺度。另外,我们还需要去除那些在边缘位置的极值点,以提高关键点的稳定性。
3.1、位置的插值
下图是二维函数离散空间得到的极值点与连续空间极值点的差别:
在这里插入图片描述
利用已知的离散空间点插值得到的连续空间极值点的方法叫做子像素插值(Sub-pixel Interpolation).对尺度空间DOG函数进行曲线拟合(子像素插值),利用DOG函数在尺度空间的泰勒展开式:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
公式推导如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
极值点的偏移量的求解如下:
在这里插入图片描述
3.2、去除边缘响应

一个定义不好的高斯差分算子的极值在横跨边缘的地方有较大的主曲率,而在垂直边缘的方向有较小的主曲率。 DOG 算子会产生较强的边缘响应,需要剔除不稳定的边缘响应点。获取特征点处的Hessian 矩阵,主曲率通过一个2x2 的Hessian 矩阵H 求出:
在这里插入图片描述
四、特征点方向分配
对上面提取的每个关键点,围绕该点选择一个窗口(圆形区域),窗口内各采样点的梯度方向构成一个方向直方图,根据直方图的峰值确定关键点的方向。关键点的尺度用来选择哪个高斯滤波图像参与计算,还用来决定窗口的大小——为了保证不同尺度下的同一关键点的方向都包含相同的信息量,那么窗口的大小必然不一样:同一个原始图像,尺度越大,窗口应该越大;反之,如果窗口大小不变,尺度越大的图像,该窗口内的信息越少.
在这里插入图片描述
做一个梯度方向的直方图,范围是0~360度,其中每10度一个柱,总共36个柱。每个采样点按照其梯度方向θ(x,y)加权统计到直方图,权值为幅度m(x,y )和贡献因子的乘积。贡献因子是采样点到关键点(窗口中心)距离的量度,距离越大,贡献因子越小.直方图的峰值代表了该关键点处邻域梯度的主方向.
在这里插入图片描述
Lowe指出,直方图的峰值确定以后,任何大于峰值80%的方向(柱)创建一个具有该方向的关键点,因此,对于多峰值(幅值大小接近)的情形,在同一位置和尺度就会产生多个具有不同方向的关键点。虽然这样的点只占15%,但是它们却能显著地提高匹配的稳定性。用每个峰值和左右两个幅值拟合二次曲线,以定位峰值的实际位置(抛物线的最高点)。峰值方向的精度高于10度。
在这里插入图片描述
所以,关键点的方向分配步骤如下:
在这里插入图片描述
五、描述符的生成
SIFT 描述子是关键点领域高斯图像梯度统计结果的一种表示。通过对关键点周围图像区域分块,计算块内梯度直方图,生成具有独特性的向量,这个向量是该区域图像信息的一种抽象,具有唯一性。 Lowe 建议描述子使用在关键点尺度空间内4×4的窗口中计算的8 个方向的梯度信息,共4×4×8 =128维向量表征.
1、确定计算描述子所需的图像区域
在这里插入图片描述
计算结果四舍五入取整。
2、将坐标轴旋转为关键点的方向,以确保旋转不变性
在这里插入图片描述
旋转后领域内采样点的新坐标为:
在这里插入图片描述
3、将领域内的采样点分配到对应的子区域内,将子区域内的梯度值分配到8 个方向上,计算其权值
在这里插入图片描述
在这里插入图片描述
4、插值计算每个种子点八个方向的梯度
在这里插入图片描述
如上图所示,将所得采样点在子区域中的下标(x’’,y’’)(图中蓝色窗口内红色点)线性插值,计算其对每个种子点的贡献。如图中的红色点,落在第0 行和第1 行之间,对这两行都有贡献。对第0 行第3 列种子点的贡献因子为dr,对第1 行第3 列的贡献因子为1-dr,同理,对邻近两列的贡献因子为dc 和1-dc,对邻近两个方向的贡献因子为do 和1-do。则最终累加在每个方向上的梯度大小为:
在这里插入图片描述
5、描述符向量元素门限化

即把方向直方图每个方向上梯度幅值限制在一定门限值一下(门限一般取0.2)

6、描述符向量元素归一化

特征向量形成后,为了去除光照变化的影响,需要对它们进行归一化处理,对于图像灰度值整体漂移,图像各点的梯度是邻域像素相减得到,所以也能去除。
在这里插入图片描述
六、匹配

采用关键点描述子的欧式距离来作为两幅图像的关键点的相似性度量。
在这里插入图片描述
七、SIFT算法的缺陷

(1)SIFT在求主方向阶段太过于依赖局部区域像素的梯度方向,有可能使得找到的主方向不准确,后面的特征向量提取以及匹配都严重依赖于主方向,即使不大偏差角度也可以造成后面特征匹配的放大误差,从而匹配不成功;
(2)图像金字塔的层取得不足够紧密也会使得尺度有误差,后面的特征向量提取同样依赖相应的尺度,发明者在这个问题上的折中解决方法是取适量的层然后进行插值。
(3)我们知道同样的景物在不同的照片中可能出现不同的形状、大小、角度、亮度,甚至扭曲;计算机视觉的知识表明通过光学镜头获取的图像,对于平面形状的两个物体它们之间可以建立射影对应,对于像人脸这种曲面物体在不同角度距离不同相机参数下获取的两幅图像,它们之间不是一个线性对应关系,就是说我们即使获得两张图像中的脸上若干匹配好的点对,还是无法从中推导出其他点的对应。
https://blog.csdn.net/CXP2205455256/article/details/41747325
https://blog.csdn.net/lhanchao/article/details/52345845#commentsedit

SIFT代码实现:

#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>
#include<opencv2/xfeatures2d.hpp>using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;Mat src, gray_src;
const char* output_title = "SIFT";
int main(int argc, char**argv) {src = imread("D:/picture/opencv/images/home.jpg");if (src.empty()) {printf("could not load image...\n");return -1;}namedWindow("input image", CV_WINDOW_AUTOSIZE);imshow("input image", src);int numFeatures = 400;Ptr<SIFT>detector = SIFT::create(numFeatures);vector<KeyPoint>keypoints;detector->detect(src, keypoints, Mat());printf("Total KeyPoints:%d\n", keypoints.size());Mat keypoint_img;drawKeypoints(src, keypoints, keypoint_img, Scalar::all(-1), DrawMatchesFlags::DEFAULT);namedWindow(output_title, CV_WINDOW_AUTOSIZE);imshow(output_title, keypoint_img);waitKey(0);return 0;
}

在这里插入图片描述


http://chatgpt.dhexx.cn/article/X0rlTuuR.shtml

相关文章

SIFT算法 特征匹配

目录 一、SIFT算法DOG尺度空间构造&#xff08;Difference of Gaussian&#xff09;关键点搜索与定位方向赋值、关键点描述 二、特征匹配 一、SIFT算法 参考链接 【OpenCV】SIFT原理与源码分析 DOG尺度空间构造&#xff08;Difference of Gaussian&#xff09; 首先是对原特…

SIFT算法详解——图像特征提取与匹配

文章目录 前言一、建立高斯差分金字塔1、建立高斯金字塔2、建立高斯差分金字塔3、建塔过程中参数的设定及相关细节问题 二、关键点(key points)位置确定1、阈值化2、在高斯差分金字塔中找极值点3、调整极值点位置4、舍去低对比度的点5、边缘效应的去除&#xff08;难点&#xf…

非常详细的sift算法原理解析

尺度不变特征变换匹配算法详解 Scale Invariant Feature Transform(SIFT) Just For Fun 转自&#xff1a;http://blog.csdn.net/zddblog/article/details/7521424 对于初学者&#xff0c;从David G.Lowe的论文到实现&#xff0c;有许多鸿沟&#xff0c;本文帮你跨越。 1、SIFT综…

【Python】:SIFT算法的实现

✨博客主页&#xff1a;米开朗琪罗~&#x1f388; ✨博主爱好&#xff1a;羽毛球&#x1f3f8; ✨年轻人要&#xff1a;Living for the moment&#xff08;活在当下&#xff09;&#xff01;&#x1f4aa; &#x1f3c6;推荐专栏&#xff1a;【图像处理】【千锤百炼Python】【深…

SIFT算法原理

SIFT算法 SIFT即尺度不变特征变换&#xff0c;是用于图像处理领域的一种描述。这种描述具有尺度不变性&#xff0c;可在图像中检测出关键点&#xff0c;是一种局部特征描述子。 一、SIFT算法特点&#xff1a; 1、具有较好的稳定性和不变性&#xff0c;能够适应旋转、尺度缩放…

计算机视觉——SIFT算法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、SIFT算法特点二、SIFT算法实质三、SIFT算法实现特征匹配主要有以下流程&#xff1a;1、**特征点位置和尺度的提取**&#xff1a;2、**特征点方向的提取**3、…

SIFT(尺度不变特征变换)算法

目录 SIFT 1、生成高斯差分金字塔&#xff0c;尺度空间构建 2、空间极值点检测 3、稳定关键点的精确定位 4、稳定关键点方向信息分配 5、关键点描述 6、特征点匹配 SIFT SIFT&#xff1a;Scale-Invariant Feature Trainsform即尺度不变特征变换&#xff0c;这是一种图像…

SIFT算法

1. SIFT简介 尺度不变特征转换(Scale-invariant feature transform或SIFT)是一种电脑视觉的算法用来侦测与描述影像中的局部性特征&#xff0c;它在空间尺度中寻找极值点&#xff0c;并提取出其位置、尺度、旋转不变量&#xff0c;此算法由 David Lowe在1999年所发表&#xff…

SIFT算法详解(附有完整代码)

说明&#xff1a;本文旨在给出 SIFT 算法的具体实现&#xff0c;而在 SIFT 详解上只是做出简单介绍&#xff0c;在这里可以给大家推荐一篇好文&#xff1a;https://blog.csdn.net/zddblog/article/details/7521424&#xff1b;结合这篇文章和下文的具体代码实现&#xff0c;我相…

SIFT算法详解

大纲 引言一、高斯金字塔二、高斯差分金字塔三、特征点处理1.阈值化2.非极大值抑制3. 二阶泰勒修正4.低对比度去除5.边缘效应去除 四、特征点描述子1. 确定特征点区域方向2. 特征点区域描述子 总结参考&#xff1a; 引言 SIFT算法是为了解决图片的匹配问题&#xff0c;想要从图…

全网最详细SIFT算法原理实现

文章目录 一、SIFT算法1.1什么是SIFT算法&#xff1f;1.2SIFT算法特点 二、SIFT算法实质2.1SIFT算法实现特征匹配主要有以下三个流程&#xff1a; 三、SIFT算法原理3.1图像金字塔3.2创建图像高斯金字塔3.3高斯金字塔创建总图 四、尺度空间五、高斯差分金字塔5.1极值点(Key poin…

uniapp如何下拉刷新?其实简简单单

uniapp如何上拉刷新&#xff1f;其实简简单单 不论是微信小程序和app上拉刷新功能都是非常常用的&#xff0c;可以说是每个app的标配。 文章目录 uniapp如何上拉刷新&#xff1f;其实简简单单第一步&#xff1a;1.1app全局开启下拉刷新1.2 app中单个页面开启下拉刷新 第二步2.…

uni-app(9)— 下拉刷新以及关闭下拉刷新,上拉加载(页面触底)

此文为uni-app总结笔记&#xff08;9&#xff09;— 下拉刷新以及关闭下拉刷新&#xff0c;上拉加载&#xff08;页面触底&#xff09; 下拉刷新 开启下拉刷新 在uni-app中有三种方式开启下拉刷新 方法一&#xff1a; 需要在 pages.json 里&#xff0c;找到的当前页面的pag…

上拉刷新和下拉刷新的实现

先来两张效果图 关于下拉刷新&#xff0c;Google提供了一个布局SwipRefreshLayout,它里面可以包涵一个滑动控件&#xff0c;然后你可以设置它的刷新事件就OK了&#xff0c;非常简单用。但是上拉刷新就有点麻烦了。网上很多方法都是给recyclerview添加footer的方法&#xff0c;我…

Flutter 实现下拉刷新和上拉加载

参考 Flutter下拉刷新和上拉加载更多 下拉刷新 上拉加载更多 下拉刷新直接用flutter自带的控件RefreshIndicator组件即可&#xff0c;上拉加载可以通过ListView 中的ScrollController 属性&#xff0c;根据 ListView 的位置来判断是否滑动到了底部来做加载更多的处理 下面用们用…

iOS 下拉刷新

移动应用开发中有这么一种场景&#xff0c;就是在列表中显示的数据刷新&#xff0c;有点击刷新按钮刷新的&#xff0c;也有现在最流行的由Twitter首先推出的下拉刷新功能&#xff0c;在IOS中&#xff0c;使用下拉刷新更新UITableView中的数据也用的非常多&#xff0c;最典型的就…

uniapp几种实现下拉刷新的方式

一.自带刷新 1.在pages.json 上进行定义 2.在页面上监听下拉动作进行需要的操作 ps&#xff1a;一定要手动停止刷新&#xff0c;否则会一直刷新 自带刷新的优点&#xff1a;相对稳定&#xff0c;写法相对简单 自带刷新的缺点&#xff1a;样式上固定的 所以不能满足全部人的需…

小程序下拉刷新的实现

小程序下拉刷新 1.使用onPullDownRefresh()这个方法来实现下拉刷新 例子如下&#xff1a; // 下拉刷新onPullDownRefresh: function () {wx.showNavigationBarLoading() //在标题栏中显示加载图标setTimeout(() > {wx.hideNavigationBarLoading(); //完成停止加载wx.stopP…

Android 下拉刷新实践

1. 手动实现一个下拉刷新功能。 2. 效果图&#xff1a; 3. view结构 4.实现思路 <com.luocc.tim.recycler.RefreshLayoutandroid:layout_width"match_parent"android:layout_height"wrap_content"android:orientation"vertical"><Tex…

【uniapp】页面下拉刷新

目录 一、全局 二、局部 1、一个页面一个下拉刷新 2、一个页面多个下拉刷新&#xff08;切换时滚动条回到顶部&#xff09; 3、一个页面多个下拉刷新&#xff08;切换时恢复滚动条位置&#xff09; 一、全局 修改pages.json的"enablePullDownRefresh": true, …