当前位置: 首页 > news >正文

高光谱拼接算法(四)SIFT 特征匹配

  1. 特征描述#
    在上一篇中,我们完成了 SIFT 特征点检测的全部流程,得到了一批位置精确、尺度明确、对比度足够且非边缘的稳定特征点,每个特征点携带的信息是:

现在便正式来到下一部分:

拿到了这些关键点后,怎么在另一张图像中找到它?也就是构造描述子。

1.1 获取特征主方向#
在 SIFT 的流程里,我们需要为每个特征点赋予一个主方向,这是为了让描述子具有旋转不变性。

我们直接展开具体过程来理顺其原理,首先:

以单个特征点为例,下一步是在该特征点对应的 Gaussian 图像
上,以特征点为中心取一个邻域窗口,对窗口内每个像素计算梯度幅值和方向。

说明两个细节:

操作对象不是 DoG 金字塔,因为 DoG 是差分响应图,Gaussian 才具有原始图像信息。
邻域窗口的大小一般以特征点尺度为基准,取约覆盖
大小的二维邻域。
现在再来看出现的两个新词:梯度幅值和梯度方向,我们同样通过中心差分近似计算,公式如下:

梯度幅值:
梯度方向:

虽然二者出现的有些突兀,但是从梯度本身的概念出现其实不难理解,这是为了得到特征点所代表的局部特征的变化强度和方向,用于后续的描述子构建。
9610cd42-798b-480a-9c06-1ca50f5f6cfb.png

1.1.1 方向直方图#
现在,对于窗口内的每个像素,我们都有了一个响应值和一个代表方向的角度,SIFT 用直方图来统计这些方向,具体如下:

设计直方图共 36 个 bin,每个 bin 覆盖

)。
每个像素根据其梯度方向投票到对应的 bin 中。
投票权重不是简单的 +1,而是加权投票:
贡献
其中,
是刚刚计算的梯度幅值,
则是以关键点为中心的高斯权重(取
)。
e68d8d36-1178-4266-a638-da5868f12677.png

需要补充的是,在实际实现中,SIFT 并不会将一个像素的全部贡献直接投给某一个方向 bin,而是采用线性插值进行分配。

这是因为梯度方向通常不是某个 bin 的中心值。如果全部投给其中一个 bin,当方向仅发生极小变化时(如
),投票对象便会突然切换,导致方向直方图出现不连续的跳变。
因此,SIFT 会根据梯度方向距离相邻两个 bin 中心的远近,将梯度贡献按比例分配给这两个 bin。例如,对于方向为
的像素,则总投票量会按照和区间中心的距离比例分别累加到 相邻两个方向 bin(如覆盖

的两个 bin) 中,而不是全部投给其中一个。

这样,即使梯度方向发生轻微变化,方向直方图也会平滑变化,从而减少量化误差,提高主方向估计的稳定性。

再解释两个设计细节:

为什么用梯度幅值加权:梯度幅值代表"这个方向的变化有多强"。如果某个像素的梯度幅值很小,说明它附近的灰度变化很微弱,其方向信息受噪声影响较大,不应赋予过高的投票权重。
为什么还要高斯加权:离关键点中心越远的像素,越容易受到图像变形、遮挡等因素的影响。高斯加权是为了确保关键点中心附近的信息最可靠,边缘区域仅供参考。
1.1.2 主方向与辅助方向#
现在,刚刚得到的直方图的最高峰值对应的方向就是该特征点的主方向。

然后,为了获得更精确的角度值,SIFT 会对峰值及其相邻两个 bin 做抛物线插值:

其中


分别是峰值 bin 及其左右相邻 bin 的投票数,

举个例子:

步骤 计算公式 / 说明 代入数值 计算结果

  1. 确定峰值与相邻值 提取峰值 bin 及其左右相邻 bin 的投票数
    ,
    ,

  2. 计算分子 左侧投票数减去右侧投票数

  3. 计算分母 峰值投票数的两倍减去两侧投票数之和,再乘 2

  4. 计算修正偏移量 (分子 / 分母) × bin 宽度

  5. 得出精确角度 峰值角度 + 修正偏移量
    至此,每个特征点携带的信息扩展为四维:

但这还不够,如果一个关键点位于"十字交叉"这类双向结构上,可能有两个同样显著的方向。因此,SIFT 为这张情况进行了专门处理:

如果存在某个非主峰 bin,其值达到主峰值的 80% 以上,则为该关键点创建一个新的辅助方向。

也就是说:一个特征点可能会对应多组
, 这会在后续匹配中增加成功的概率。

到这里,我们为每个特征点扩展了一维方向信息,下一步,它就可以帮助我们生成具有旋转不变性的描述子。

1.2 特征描述子#
现在我们有了位置、尺度、方向这些关键信息,最后一步就是:如何用一个向量描述这个关键点周围的信息?

SIFT 描述子的设计思路概括如下:

在特征点坐标周围取邻域,进行旋转归一获取旋转不变性,再次使用梯度方向直方图投票组成描述子,并进行合理的处理尽可能使其对光照影响不敏感。

287c1e5d-de75-47b6-a287-c4b55e4d6640.png

1.2.1 生成描述子#
现在,再次取约
大小邻域窗口,将其划分为
个子区域(此区域数一般固定)。

下一步,对整个邻域中的像素旋转矩阵,以特征值为中心旋转到主方向

这样无论原始图像怎么旋转,描述子看到的都是"正面朝上"的局部区域。
这一步就是让匹配具有旋转不变性的关键,如果同一个局部区域在另一幅图中被旋转,其会被旋转归一化后再生成对应描述子,这样就抹平了旋转带来的影响。

继续,在每个子区域内,计算各像素的梯度方向并减去主方向,保证描述子始终以关键点主方向作为参考方向。继续投票到一个 8 个 bin 的方向直方图中,每个 bin 覆盖

投票权重依然是梯度幅值乘以高斯权重,但这次高斯窗口覆盖整个区域,
取区域宽度的一半。

而和上面相同的,这里实际上也使用了插值。我们从一个问题出发:

如果某个像素刚好位于两个子区域的边界,或者梯度方向恰好落在两个方向 bin 的交界处,该如何投票?

如果直接把它全部投给其中一个子区域或一个方向 bin,那么像素只发生极小的位移,就可能导致投票对象突然改变,从而使描述子发生明显跳变,同样的问题也存在于方向统计中。

因此,SIFT 并不会将一个像素的贡献全部投给某一个子区域和某一个方向 bin,而是采用三线性插值(Trilinear Interpolation)进行加权分配。

一个像素的梯度贡献会按照距离大小,分别分配给邻近的 4 个子区域和每个子区域中相邻的 2 个方向 bin,最多影响 8 个统计单元。
ceeec9f8-1a29-43f8-9489-9ab699404cc3.png

现在,每个
子区域投票完的直方图中每个 bin 都有对应投票结果,共 8 个值,组成一个 8 维向量,总共:

这个128 维的特征向量就是 SIFT 描述子。

1.2.1 优化描述子#
到这里还没有结束:原始 128 维向量还不能直接用,因为光照差异会导致梯度幅值整体放大或缩小。

所以首先要对结果做 L2 归一化:

这样就能抵消光照带来的整体线性缩放问题。
但问题还没完全解决:如果图像局部出现过曝或过暗,某些方向上的梯度会异常大,归一化后依然会扭曲整体分布。

因此 SIFT 加了一步截断:


中大于 0.2 的元素截断为 0.2,然后再次 L2 归一化。

注意这是第二次 L2 归一化,因为截断后向量长度再次发生变化,需要重新归一化。
0.2 的作用就是限制单个方向上的最大贡献,避免光照饱和导致的梯度异常主导整个描述子。

9cabc6c7-02a8-4345-8fa6-e018592b6a06.png

最终,SIFT 特征点的完整信息如下:

这便是 SIFT 特征描述的完整逻辑,现在,我们就可以应用其进行匹配。

  1. 特征匹配#
    有了描述子,特征匹配就转化为了一个向量匹配问题:

对于第一张图像中的每个特征点,在第二张图像中找到"最相似"的特征点。

由于 SIFT 描述子经过了两次 L2 归一化,各维度已经处于统一的尺度,因此可以直接使用欧氏距离衡量两个描述子的相似程度,距离越小,说明两者的局部结构越接近:

但就像给大模型搭 Agent,怎么使用这个公式同样关键:

2.1 暴力匹配#
最简单的匹配方式就是暴力匹配:

对于图像
中的每个特征点,计算它与图像
中所有特征点的欧氏距离,取距离最小的那个作为匹配结果。

整个过程十分直接,因此也称为最近邻匹配(Nearest Neighbor Matching)。
其时间复杂度为:
, 如果两幅图各有几千个特征点,总计算量通常在百万到千万次距离计算量级,现代 CPU 一般可以在几十毫秒内完成。

当特征点数量较少时,暴力匹配已经足够高效。但随着特征点数量不断增加,逐一计算所有距离的代价会迅速增长。因此,工程中通常会采用 FLANN 等近似最近邻搜索算法,来提高匹配速度。

不过,暴力匹配有一个明显的问题:

如果某个特征点在另一张图像中根本没有真正的对应点怎么办?

暴力匹配仍然会返回一个距离最小的结果,即使这个"最近邻"实际上只是所有候选中最不像那么不像的那个。

因此,SIFT 原论文还提出了一个的筛选策略:比率测试(Ratio Test)。

2.2 Ratio Test 比率测试#
比率测试的逻辑并不复杂:

对于每个查询特征点,找到描述子空间中距离最近的两个候选点,其距离分别记为

,仅当

时,才认为该匹配有效。

其中,
为最近邻距离,
为次近邻距离,论文中推荐

a4c6d29c-bb7e-40b1-841e-60db3a41eae7.png

http://www.cnnetsun.cn/news/3261623.html

相关文章:

  • 基于国产FPGA 易灵思钛金系列TJ375的CoaXPress CXP数据测试
  • Canva × ChatGPT营销自动化落地指南:从零搭建日均产出50条爆款素材的SOP(附私有化提示词库)
  • 云环境下的数据库统一管理:跨平台工具选型策略
  • Zotero文献库重复项终极清理指南:5分钟实现学术资料高效管理
  • Midjourney seed值调参黄金法则:从随机噪声到像素级复刻,93.7%用户忽略的3个隐藏参数
  • Android ParcelFileDescriptor 实战:3步构建跨进程文件/流传输通道
  • AI重塑IT行业:招聘趋势、技能转型与未来机遇分析
  • 锂离子电池组电压平衡方案:MP2672A与PIC18F46K22实现
  • 【OneNote笔记生产力天花板】:Copilot智能体配置全攻略——实测响应速度提升4.8倍,仅限Windows 11 24H2最新版
  • 【Bug已解决】Claude CLAUDE.md not loading / Project config ignored — Claude 项目配置不加载解决方案
  • PIC18LF45K42驱动EPT-14A4005P蜂鸣器的工业级音频警报方案
  • 【大数据毕业设计】基于分布式存储的济南旅游热点数据分析系统的设计与实现 济南文旅景区大数据统计与可视化监测系统(源码+文档+远程调试,全bao定制等)
  • ROS 2 Humble/Iron 可组合节点实战:3步将常规Node改造为Component(附CMake/Launch配置)
  • 企业级AI Agent平台架构设计:任务编排、工具调用与结果验证实战
  • RyzenAdj终极指南:3分钟掌握AMD处理器性能调优
  • 提示词工程:从基础概念到RAG实战的工程化方法
  • 2024-2026年AI Agent开发学习路线:从零到全栈实战指南
  • ncmdump:突破网易云音乐NCM格式限制的终极解密解决方案
  • 从技术机制到生态建设,Open Genesis如何构建AI时代的Web3共识网络
  • 欧盟监管视角下 AI 赋能钓鱼攻击演化与分层检测防御体系研究
  • PIC18F57Q43与A3910电机驱动方案设计与优化
  • 基于STM32的智能家居照明系统:从继电器控制到完整物联网方案
  • Unity中利用Odin序列化多层字典,实现高效可视化数据配置
  • 工业负载控制方案:MCU与智能功率驱动器的应用
  • MA12070与CEC1302构建高效D类音频系统方案
  • 工业负载控制方案:TPD2017FN与PIC18F57Q43的优化设计
  • STM32F103C8T6 定时器中断实战:4个独立按键+数码管实现交通灯3模式切换
  • 如何用BackgroundRemover快速实现专业级背景去除:完整入门指南
  • 23 组件生命周期:aboutToAppear、aboutToDisappear、onPageShow
  • 如何构建企业级Python DDD架构:5个领域驱动设计实战策略