计算机视觉——SIFT算法

article/2025/10/26 15:43:59

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、SIFT算法特点
  • 二、SIFT算法实质
  • 三、SIFT算法实现特征匹配主要有以下流程:
    • 1、**特征点位置和尺度的提取**:
    • 2、**特征点方向的提取**
    • 3、**特征提取汇总**
    • 4、**特征描述**
    • 4、**特征匹配**
  • 四、提取关键点可视化
  • 五、匹配地理标记图像
    • 1.源码
    • 2.运行结果
  • 总结


前言

SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。


一、SIFT算法特点

1、具有较好的稳定性和不变性,能够适应旋转、尺度缩放、亮度的变化,能在一定程度上不受视角变化、仿射变换、噪声的干扰。
2、区分性好,能够在海量特征数据库中进行快速准确的区分信息进行匹配
3、多量性,就算只有单个物体,也能产生大量特征向量
4、高速性,能够快速的进行特征向量匹配
5、可扩展性,能够与其它形式的特征向量进行联合

二、SIFT算法实质

在不同的尺度空间上查找关键点,并计算出关键点的方向。
在这里插入图片描述

三、SIFT算法实现特征匹配主要有以下流程:

1、特征点位置和尺度的提取

在 特征提取 步骤下,其主要应用了图像金字塔 和 图像尺度空间
1.图像金字塔
将图像经过一系列的降采样,不同大小的图片其空间形状像是金字塔,因此得名。
2. 图像尺度空间
将图像经过不同尺度(σ)的高斯卷积算子,进而得到不同高斯尺度(σ)下的图像

具体步骤如下:
1.将相同size的相邻高斯尺度之间的灰度图像进行减法运算,进而得到高斯差分图像。可以看得出其边缘特征比较明显。
2.然后在高斯差分图像上检测特征点。

  • 假若一个像素点比其 周围8个点 + 相邻两个高斯差分图像上对应的18个点 的像素值(共26个)都大或都小,则该点为特征点。
  • 该特征点的尺度信息来自于 1. 检测出特征点所在的高斯差分图像,其图像的与原图的长宽比例 2. 检测出特征点所在的高斯差分图像的高斯尺度

2、特征点方向的提取

选择好特征点之后,还需要提取出特征点特方向信息。在特征点所在的 系数*高斯尺度(σ)为长宽的正方形区域内,求像素点之间梯度变化的方向。
将方向划分到以45°为间隔的8个方向内 进行统计, 最多的方向则为该特征点的主方向

3、特征提取汇总

SIFT算法 有了特征点的位置、尺度、方向三个信息,之后再依据尺度、方向对特征点进行描述,则特征点的特征向量将具有尺度不变性和旋转不变性。
在这里插入图片描述

4、特征描述

依据尺度、方向对特征点进行描述。

尺度信息体现在特征点的描述区域范围,是系数*尺度

方向信息:

以特征点的主方向作为特征描述的X轴,在其坐标系的四个象限上分别划出2*2个小格子,每个小格子分别对格子中的灰度变化方向进行统计。

每个小格子统计出来一个按照8个方向划分,8个方向的数量 归一化后的结果,成为一个8维的向量。

一共4个象限即44个小格子, 44*8=128, 最终SIFT的特征点将用128维向量表示。

(如果主方向为45°的倍数,按其作为主方向去描述后,有些位置的灰度值和方向需要通过插值得到)
在这里插入图片描述

4、特征匹配

考虑到特征向量中的元素为浮点数,向量之间的距离计算采用欧式距离进行计算。

当距离小于某一阈值时,认为两个特征点匹配上了,即匹配成功。
在这里插入图片描述

四、提取关键点可视化

from numpy import loadtxt, array, concatenate, zeros, dot, arccosfrom numpy.linalg import linalg
from pylab import *
from PIL import Image
from numpy import *
import os
from numpy import loadtxt, arange, cos, sin, pidef process_image(imagename, resultname, params="--edge-thresh 10 --peak-thresh 5"):"""处理一幅图像,然后将结果保存在文件中"""if imagename[-3:] != 'pgm':# 创建一个pgm文件im = Image.open(imagename).convert('L')im.save('tmp.pgm')imagename = 'tmp.pgm'cmmd = str("C:/Users/Administrator/Desktop/vlfeat-0.9.20-bin/vlfeat-0.9.20/bin/win64/sift.exe " + imagename + " --output=" + resultname + " " + params)os.system(cmmd)print('processed', imagename, 'to', resultname)def read_features_from_file(filename):"""读取特征值属性值,然后将其以矩阵形式返回"""f = loadtxt(filename)return f[:, :4], f[:, 4:]  # 特征位置,描述子def plot_features(im, locs, circle=False):"""显示带有特征的图像输入:im(数组图像),locs(每个特征的行、列、尺度和方向角度)"""def draw_circle(c,r):t = arange(0,1.01,.01)*2*pix = r*cos(t) + c[0]y = r*sin(t) + c[1]plot(x,y,'b',linewidth=2)imshow(im)if circle:for p in locs:draw_circle(p[:2],p[2])else:plot(locs[:,0],locs[:,1],'ob')axis('off')returndef match(desc1, desc2):"""对于第一幅图像的每个描述子,选取其在第二幅图像中的匹配输入:desc1(第一幅图像中的描述子),desc2(第二幅图像中的描述子)"""desc1 = array([d/linalg.norm(d) for d in desc1])desc2 = array([d/linalg.norm(d) for d in desc2])dist_ratio = 0.6desc1_size = desc1.shapematchscores = zeros((desc1_size[0],1), 'int')desc2t = desc2.T    #预先计算矩阵转置for i in range(desc1_size[0]):dotprods = dot(desc1[i,:], desc2t) #向量点乘dotprods = 0.9999*dotprods# 反余弦和反排序,返回第二幅图像中特征的索引index = argsort(arccos(dotprods))# 检查最近邻的角度是否小于dist_ratio乘以第二近邻的角度if arccos(dotprods)[index[0]] < dist_ratio * arccos(dotprods)[index[1]]:matchscores[i] = int(index[0])return matchscoresdef match_twosided(desc1,decs2):"""双向对称版本的match"""matches_12 = match(desc1, decs2)matches_21 = match(decs2, decs2)ndx_12 = matches_12.nonzero()[0]# 去除不对称匹配for n in ndx_12:if matches_21[int(matches_12[n])] != n:matches_12[n] = 0return matches_12def appendimages(im1, im2):"""返回将两幅图像并排拼接成的一幅新图像"""# 选取具有最少行数的图像,然后填充足够的空行row1 = im1.shape[0]row2 = im2.shape[0]if row1 < row2:im1 = concatenate((im1,zeros((row2-row1,im1.shape[1]))), axis=0)elif row1 > row2:im2 = concatenate((im2,zeros((row1-row2,im2.shape[1]))), axis=0)# 如果这些情况都没有,那么他们的行数相同,不需要进行填充return concatenate((im1,im2), axis=1)if __name__ == '__main__':imname = 'image/yankui1.jpg'im1 = array(Image.open(imname).convert('L'))process_image(imname, 'yankui1.sift')l1, d1 = read_features_from_file('image/yankui1.sift')figure()gray()plot_features(im1, l1, circle=True)show()

在这里插入图片描述

五、匹配地理标记图像

1.源码

源码如下(示例):

from pylab import *
from PIL import Image
from PCV.localdescriptors import sift
from PCV.tools import imtools
import pydot""" This is the example graph illustration of matching images from Figure 2-10.
To download the images, see ch2_download_panoramio.py."""download_path = "./image"  # set this to the path where you downloaded the panoramio images
path = "./image"  # path to save thumbnails (pydot needs the full system path)imlist = imtools.get_imlist(download_path)
nbr_images = len(imlist)featlist = [imname[:-3] + 'sift' for imname in imlist]
for i, imname in enumerate(imlist):sift.process_image(imname, featlist[i])matchscores = zeros((nbr_images, nbr_images))for i in range(nbr_images):for j in range(i, nbr_images):  # only compute upper triangleprint('comparing ', imlist[i], imlist[j])l1, d1 = sift.read_features_from_file(featlist[i])l2, d2 = sift.read_features_from_file(featlist[j])matches = sift.match_twosided(d1, d2)nbr_matches = sum(matches > 0)print('number of matches = ', nbr_matches)matchscores[i, j] = nbr_matches
print("The match scores is: \n", matchscores)# copy values
for i in range(nbr_images):for j in range(i + 1, nbr_images):  # no need to copy diagonalmatchscores[j, i] = matchscores[i, j]#可视化threshold = 2  # min number of matches needed to create linkg = pydot.Dot(graph_type='graph')  # don't want the default directed graphfor i in range(nbr_images):for j in range(i + 1, nbr_images):if matchscores[i, j] > threshold:# first image in pairim = Image.open(imlist[i])im.thumbnail((100, 100))filename = path + str(i) + '.png'im.save(filename)  # need temporary files of the right sizeg.add_node(pydot.Node(str(i), fontcolor='transparent', shape='rectangle', image=filename))# second image in pairim = Image.open(imlist[j])im.thumbnail((100, 100))filename = path + str(j) + '.png'im.save(filename)  # need temporary files of the right sizeg.add_node(pydot.Node(str(j), fontcolor='transparent', shape='rectangle', image=filename))g.add_edge(pydot.Edge(str(i), str(j)))
g.write_png('whitehouse.png')

2.运行结果

imag文件夹中放入同一场景的序列图像(如下):
ps:场景为集美大学陈延奎图书馆
在这里插入图片描述

运行后将图像进行两两匹配,可视化后如图所示:
在这里插入图片描述


总结

匹配地理标记图像可视化的实验结果可以看出,匹配连接的顺序大致正确,

SIFT算法的优缺点:

SIFT 算法在图片的不变特征提取领域拥有非常大的优点,但仍存在个别缺点:
实时性偏低,运行速度不快
有些情况下特征点较少
对边缘光滑的目标图片无法准确提取特征点等缺点
对模糊的图片和边缘平滑的图片,检测出特征点过少

参考:
SIFT算法详解:https://blog.csdn.net/zddblog/article/details/7521424


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

相关文章

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, …

uniapp 下拉刷新

uniapp 下拉刷新&#xff08;全局&单页面&#xff09; 全局设置 在pages.json文件的globalStyle对象中开启enablePullDownRefresh属性 单页面 在pages.json文件中的pages数组中找到对应的页面&#xff0c;在对应页面的style属性中开启enablePullDownRefresh属性 下拉刷…

Android 下拉刷新框架实现

前段时间项目中用到了下拉刷新功能&#xff0c;之前在网上也找到过类似的demo&#xff0c;但这些demo的质量参差不齐&#xff0c;用户体验也不好&#xff0c;接口设计也不行。最张没办法&#xff0c;终于忍不了了&#xff0c;自己就写了一个下拉刷新的框架&#xff0c;这个框架…

Android中实现下拉刷新

需求&#xff1a;项目中的消息列表界面要求实现类似sina微博的下拉刷新&#xff1b; 思路&#xff1a;一般的消息列表为ListView类型&#xff0c;将list加载到adapter中&#xff0c;再将adapter加载到ListView中&#xff0c;从而实现消息列表的展示。而下拉刷新要求给消息列表…

微信小程序下拉刷新

一、如何设置微信小程序所有页面都可以下拉刷新呢&#xff1f; 1、在app.json的"window"中进行配置 &#xff08;1&#xff09;把"backgroundTextStyle":“light"改为"backgroundTextStyle”:“dark” &#xff08;2&#xff09;添加"enab…

下拉刷新上拉加载

目录 原理实现效果 原理 想必使用过微信开发工具的应该都接触过上拉加载下拉刷新配置。 原理呢就是通过根据当前刚开始触碰的屏幕垂直y轴距离和滑动时所触碰垂直y轴距离&#xff0c;从而来判断是上拉&#xff0c;下拉。 实现 使用的vue2 封装的组件&#xff0c;js大致思路是…

Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能

转载请注明出处&#xff1a;http://blog.csdn.net/guolin_blog/article/details/9255575 最近项目中需要用到ListView下拉刷新的功能&#xff0c;一开始想图省事&#xff0c;在网上直接找一个现成的&#xff0c;可是尝试了网上多个版本的下拉刷新之后发现效果都不怎么理想。有些…