目录
1. 算法描述
1.1 构建尺度空间
1.2 LoG近似DoG找到关键点
1.3 除去不好的特征点
1.4 关键点的表示
1.5 关键点描述子的生成
1.6 根据SIFT进行匹配
2. 实验要求
3.实验过程
3.1 实验数据集
3.2 sift特征提取
3.3 特征匹配
3.4 匹配筛选
3.5 地理标记图像匹配
4.RANSAC算法理解及实验分析
4.1 RANSAC的基本假设是:
4.2 概述
4.3 RANSAC算法原理
4.4 算法步骤
4.5 RANSAC算法实验过程
分析总结:
5. 总结
5.1 SIFT特征特性:
5.2 SIFT特征的缺点
5.3 SIFT特征的用途
5.4 实验过程遇到的问题
特征描述子就是对关键点提取特征的过程,应该具备可重复性、可区分性、准确性、有效性和鲁棒性。SIFT(Scale-Invariant Feature Transform)是一种特征描述子。该描述子具有尺度不变性和光照不变性。
这里的尺度可以理解为图像的模糊程度,就是眼睛近视的度数。尺度越大细节越少,SIFT特征希望提取所有尺度上的信息,所以对图像构建尺度空间, 也就是实用不同的平滑核对图像进行平滑。这里的平滑核选用高斯核,空间尺度有高斯核尺度决定:
其中是原图像,*是卷积符号,对应尺度下的尺度图像,是高斯核。
(x,y)是空间坐标,是尺度坐标。σ大小决定图像的平滑程度,大尺度对应图像的概貌特征,小尺度对应图像的细节特征。大的σ值对应粗糙尺度(低分辨率),反之,对应精细尺度(高分辨率)。
图像金字塔的建立:对于一幅图像I,建立其在不同尺度(scale)的图像,也成为子八度(octave),这是为了scale-invariant,也就是在任何尺度都能够有对应的特征点,第一个子八度的scale为原图大小,后面每个octave为上一个octave降采样的结果,即原图的1/4(长宽分别减半),构成下一个子八度(高一层金字塔)。
尺度空间的所有取值,i为octave的塔数(第几个塔),s为每塔层数
由图片size决定建几个塔,每塔几层图像(S一般为3-5层)。0塔的第0层是原始图像(或你double后的图像),往上每一层是对其下一层进行Laplacian变换(高斯卷积,其中σ值渐大,例如可以是σ, k*σ, k*k*σ…),直观上看来越往上图片越模糊。塔间的图片是降采样关系,例如1塔的第0层可以由0塔的第3层down sample得到,然后进行与0塔类似的高斯卷积操作。
为了寻找尺度空间的极值点,每一个采样点要和它所有的相邻点比较,看其是否比它的图像域和尺度域的相邻点大或者小。如图所示,中间的检测点和它同尺度的8个相邻点和上下相邻尺度对应的9×2个点共26个点比较,以确保在尺度空间和二维图像空间都检测到极值点。 一个点如果在DOG尺度空间本层以及上下两层的26个领域中是最大或最小值时,就认为该点是图像在该尺度下的一个特征点,如图所示。
同一组中的相邻尺度(由于k的取值关系,肯定是上下层)之间进行寻找
s=3的情况
在极值比较的过程中,每一组图像的首末两层是无法进行极值比较的,为了满足尺度变化的连续性,我们在每一组图像的顶层继续用高斯模糊生成了 3 幅图像,高斯金字塔有每组S+3层图像。DOG金字塔每组有S+2层图像.
这一步本质上要去掉DoG局部曲率非常不对称的像素。
通过拟和三维二次函数以精确确定关键点的位置和尺度(达到亚像素精度),同时去除低对比度的关键点和不稳定的边缘响应点(因为DoG算子会产生较强的边缘响应),以增强匹配稳定性、提高抗噪声能力,在这里使用近似Harris Corner检测器。
①空间尺度函数泰勒展开式如下:,对上式求导,并令其为0,得到精确的位置, 得
②在已经检测到的特征点中,要去掉低对比度的特征点和不稳定的边缘响应点。去除低对比度的点:把公式(2)代入公式(1),即在DoG Space的极值点处D(x)取值,只取前两项可得:
若 ,该特征点就保留下来,否则丢弃。
③边缘响应的去除
一个定义不好的高斯差分算子的极值在横跨边缘的地方有较大的主曲率,而在垂直边缘的方向有较小的主曲率。主曲率通过一个2×2 的Hessian矩阵H求出:
D的主曲率和H的特征值成正比,令α为较大特征值,β为较小的特征值,则
(r + 1)2/r的值在两个特征值相等的时候最小,随着r的增大而增大,因此,为了检测主曲率是否在某域值r下,只需检测
转存失败重新上传取消
if (α+β)/ αβ> (r+1)2/r, throw it out. 在Lowe的文章中,取r=10。
上一步中确定了每幅图中的特征点,为每个特征点计算一个方向,依照这个方向做进一步的计算, 利用关键点邻域像素的梯度方向分布特性为每个关键点指定方向参数,使算子具备旋转不变性。
为(x,y)处梯度的模值和方向公式。其中L所用的尺度为每个关键点各自所在的尺度。至此,图像的关键点已经检测完毕,每个关键点有三个信息:位置,所处尺度、方向,由此可以确定一个SIFT特征区域。
首先将坐标轴旋转为关键点的方向,以确保旋转不变性。以关键点为中心取8×8的窗口。
Figure.16*16的图中其中1/4的特征点梯度方向及scale,右图为其加权到8个主方向后的效果。
图左部分的中央为当前关键点的位置,每个小格代表关键点邻域所在尺度空间的一个像素,利用公式求得每个像素的梯度幅值与梯度方向,箭头方向代表该像素的梯度方向,箭头长度代表梯度模值,然后用高斯窗口对其进行加权运算。
图中蓝色的圈代表高斯加权的范围(越靠近关键点的像素梯度方向信息贡献越大)。然后在每4×4的小块上计算8个方向的梯度方向直方图,绘制每个梯度方向的累加值,即可形成一个种子点,如图右部分示。此图中一个关键点由2×2共4个种子点组成,每个种子点有8个方向向量信息。这种邻域方向性信息联合的思想增强了算法抗噪声的能力,同时对于含有定位误差的特征匹配也提供了较好的容错性。
计算keypoint周围的16*16的window中每一个像素的梯度,而且使用高斯下降函数降低远离中心的权重。
在每个4*4的1/16象限中,通过加权梯度值加到直方图8个方向区间中的一个,计算出一个梯度方向直方图。
这样就可以对每个feature形成一个4*4*8=128维的描述子,每一维都可以表示4*4个格子中一个的scale/orientation. 将这个向量归一化之后,就进一步去除了光照的影响。
生成了A、B两幅图的描述子,(分别是k1*128维和k2*128维),就将两图中各个scale(所有scale)的描述子进行匹配,匹配上128维即可表示两个特征点匹配上了。当两幅图像的SIFT特征向量生成后,下一步我们采用关键点特征向量的欧式距离来作为两幅图像中关键点的相似性判定度量。取图像1中的某个关键点,并找出其与图像2中欧式距离最近的前两个关键点,在这两个关键点中,如果最近的距离除以次近的距离少于某个比例阈值,则接受这一对匹配点。降低这个比例阈值,SIFT匹配点数目会减少,但更加稳定。最近邻距离与次近邻距离的方法,距离比率ratio小于某个阈值的认为是正确匹配。
建议的ratio取值原则如下:
ratio=0. 4 对于准确度要求高的匹配;
ratio=0. 6 对于匹配点数目要求比较多的匹配;
ratio=0. 5 一般情况下。
也可按如下原则:当最近邻距离<200时ratio=0. 6,反之ratio=0. 4。ratio的取值策略能排分错误匹配点。
(1) 针对自己所处的环境,拍摄多张图片(注意要来自不同场景),构造出一个小的数据集(15张以上)
(2) 实现数据集中,每张图片的SIFT特征提取,并展示特征点
(3) 给定两张图片,计算其SIFT特征匹配结果
(4)给定一张输入的图片,在数据集内部进行检索,输出与其匹配最多的三张图片
比如输入:
3.2.1 源代码
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from PCV.localdescriptors import sift
from PCV.localdescriptors import harris
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:/windows/fonts/SimSun.ttc", size=14)
imname = 'D:/ComputerVision_code/img/sdl11.jpg'
im = array(Image.open(imname).convert('L'))
sift.process_image(imname, 'empire.sift')
l1, d1 = sift.read_features_from_file('empire.sift')
figure()
gray()
subplot(121)
sift.plot_features(im, l1, circle=False)
title(u'SIFT特征',fontproperties=font)
# 检测harris角点
harrisim = harris.compute_harris_response(im)
subplot(122)
filtered_coords = harris.get_harris_points(harrisim, 6, 0.1)
imshow(im)
plot([p[1] for p in filtered_coords], [p[0] for p in filtered_coords], '*')
axis('off')
title(u'Harris角点',fontproperties=font)
show()
3.2.2 图片特征提取结果
3.2.3 小结
sift描述子同Harris角点算法一样,具有尺度不变性、光照不变性和旋转不变性的特点,但两个算法检测的结果能看到明显的区别,sift算法检测到的特征点明显比Harris算法的更多,更丰富,而且运算速度比较快,定位精度也比较高,体现出了sift算法特征检测的优越性。
3.3.1 源代码
from PIL import Image
from pylab import *
import sys
from PCV.localdescriptors import sift
if len(sys.argv) >= 3:
im1f, im2f = sys.argv[1], sys.argv[2]
else:
im1f = 'D:/ComputerVision_code/img/sdl11.jpg'
im2f = 'D:/ComputerVision_code/img/sdl12.jpg'
im1 = array(Image.open(im1f))
im2 = array(Image.open(im2f))
sift.process_image(im1f, 'out_sift_1.txt')
l1, d1 = sift.read_features_from_file('out_sift_1.txt')
sift.process_image(im2f, 'out_sift_2.txt')
l2, d2 = sift.read_features_from_file('out_sift_2.txt')
matches = sift.match_twosided(d1, d2)
print ('{} matches'.format(len(matches.nonzero()[0])))
figure()
gray()
sift.plot_matches(im1, im2, l1, l2, matches, show_below=True)
title('{} matches'.format(len(matches.nonzero()[0])))#设置子图标题
show()
3.3.2 匹配结果
3.3.3 小结
从以上两个试验及结果可以看出sift算法匹配的精准度还是挺高的,虽然没能做到每一个特征点都对应起来(这当然也有图片角度不同,特征点不同不能找到匹配点的因素在),但是从埃菲尔铁塔的这组实验可看出,已经匹配的特征点,精准度非常高。
3.4.1 输入一张数据集以外的照片:
3.4.2 匹配结果
3.4.3 小结
背景模糊不清晰,还有图片像素的大小会影响到sift特征点检测算法的效果;同一角度拍摄的图片匹配度会更高,但是旋转,明暗程度,图中物体尺寸的大小都不会影响到sift算法的检测效果,因此他具有较高的稳定性和准确性,以及从大量图片中检测到目标图片的高效性。
实验代码:
# -*- coding: utf-8 -*-
from pylab import *
from PIL import Image
from PCV.localdescriptors import sift
from PCV.tools import imtools
import pydot
import os
os.environ['PATH'] = os.environ['PATH'] + (';D:/Miniconda3/Graphviz/bin')
""" This is the example graph illustration of matching images from Figure 2-10.
To download the images, see ch2_download_panoramio.py."""
#download_path = "panoimages" # set this to the path where you downloaded the panoramio images
#path = "/FULLPATH/panoimages/" # path to save thumbnails (pydot needs the full system path)
download_path = "D:/ComputerVision_code/img3" # set this to the path where you downloaded the panoramio images
path = "D:/ComputerVision_code/img3" # path to save thumbnails (pydot needs the full system path)
# list of downloaded filenames
imlist = imtools.get_imlist(download_path)
nbr_images = len(imlist)
# extract features
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 triangle
print ('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 diagonal
matchscores[j, i] = matchscores[i, j]
#可视化
threshold = 2 # min number of matches needed to create link
g = pydot.Dot(graph_type='graph') # don't want the default directed graph
for i in range(nbr_images):
for j in range(i + 1, nbr_images):
if matchscores[i, j] > threshold:
# first image in pair
im = Image.open(imlist[i])
im.thumbnail((100, 100))
filename = path + str(i) + '.jpg'
im.save(filename) # need temporary files of the right size
g.add_node(pydot.Node(str(i), fontcolor='transparent', shape='rectangle', image=filename))
# second image in pair
im = Image.open(imlist[j])
im.thumbnail((100, 100))
filename = path + str(j) + '.jpg'
im.save(filename) # need temporary files of the right size
g.add_node(pydot.Node(str(j), fontcolor='transparent', shape='rectangle', image=filename))
g.add_edge(pydot.Edge(str(i), str(j)))
g.write_png('sdl.png')
(1)为地理标记匹配准备的数据集:
* 为验证局部描述子对地理标记图像进行匹配的效果,设置了以上数据集:
* 数据集中共有两个建筑物,其中埃菲尔铁塔是角度相同,尺度不同的三张图片;
* 其余9张图片都是集美大学尚大楼分别从正面,左侧面,右侧面,远近不同的条件下所拍摄的
(2)实验结果:
(3)小结:
* 数据集中的12张图片里共有8张图片在画布中显示出了匹配连接结果,其中sdl1.jpg, sdl2.jpg, sdl4.jpg,sdl6.jpg这四张图片没有显示出来。
* 本次实验设置的“创建链接所需的最小匹配数”——threshold = 2 ,特征匹配数超过2时,将匹配数保存到矩阵中,当矩阵中的数字不为0时,将两张图片用一条线连接最后显示到画布上,匹配度越高的图片越靠前排显示出来。
* 未被显示出来的四张图片可能有两种原因:1.像素 2.匹配数小于2
自己看sdl1.jpg——sdl11.jpg和sdl6.jpg——sdl8.jpg这4张图片时,是可以判断他们能够匹配,因为两张都是大致同一角度,同一建筑的图片,但是用sift特征匹配的结果是0(如下图),没有达到我们设置的最小匹配数,所以没有匹配结果,原因可能是sdl1.jpg 的像素较高,与sdl11.jpg所检测到的特征点范围不同,所以未能匹配上。
* 从成功匹配的结果来看,局部描述子对地理标记图像进行匹配的效果还是非常可观的,埃菲尔铁塔同一角度不同尺寸的图片归为一组,尚大楼两个不同角度的图片也成功归类为两组。
* RANSAC是“RANdom SAmple Consensus(随机抽样一致)”的缩写。它可以从一组包含“局外点”的观测数据集中,通过迭代方式估计数学模型的参数。它是一种不确定的算法——它有一定的概率得出一个合理的结果;为了提高概率必须提高迭代次数。
(1)数据由“局内点”组成,例如:数据的分布可以用一些模型参数来解释;
(2)“局外点”是不能适应该模型的数据;
(3)除此之外的数据属于噪声。
* 局外点产生的原因有:噪声的极值;错误的测量方法;对数据的错误假设。
RANSAC也做了以下假设:给定一组(通常很小的)局内点,存在一个可以估计模型参数的过程;而该模型能够解释或者适用于局内点。
RANSAC算法的输入是一组观测数据,一个可以解释或者适应于观测数据的参数化模型,一些可信的参数。
RANSAC通过反复选择数据中的一组随机子集来达成目标。被选取的子集被假设为局内点,并用下述方法进行验证:
1.有一个模型适应于假设的局内点,即所有的未知参数都能从假设的局内点计算得出。
2.用1中得到的模型去测试所有的其它数据,如果某个点适用于估计的模型,认为它也是局内点。
3.如果有足够多的点被归类为假设的局内点,那么估计的模型就足够合理。
4.然后,用所有假设的局内点去重新估计模型,因为它仅仅被初始的假设局内点估计过。
5.最后,通过估计局内点与模型的错误率来评估模型。
这个过程被重复执行固定的次数,每次产生的模型要么因为局内点太少而被舍弃,要么因为比现有的模型更好而被选用。
OpenCV中滤除误匹配对采用RANSAC算法寻找一个最佳单应性矩阵H,矩阵大小为3×3。RANSAC目的是找到最优的参数矩阵使得满足该矩阵的数据点个数最多,通常令h33=1h33=1来归一化矩阵。由于单应性矩阵有8个未知参数,至少需要8个线性方程求解,对应到点位置信息上,一组点对可以列出两个方程,则至少包含4组匹配点对。
其中(x,y)表示目标图像角点位置,(x’,y’)为场景图像角点位置,s为尺度参数。
RANSAC算法从匹配数据集中随机抽出4个样本并保证这4个样本之间不共线,计算出单应性矩阵,然后利用这个模型测试所有数据,并计算满足这个模型数据点的个数与投影误差(即代价函数),若此模型为最优模型,则对应的代价函数最小。
1. 随机从数据集中随机抽出4个样本数据 (此4个样本之间不能共线),计算出变换矩阵H,记为模型M;
2. 计算数据集中所有数据与模型M的投影误差,若误差小于阈值,加入内点集 I ;
3. 如果当前内点集 I 元素个数大于最优内点集 I_best , 则更新 I_best = I,同时更新迭代次数k ;
4. 如果迭代次数大于k,则退出 ; 否则迭代次数加1,并重复上述步骤;
(1)实验数据集
(2)
(3)
(4)验证猜想实验(不同光线,拍摄角度,图片旋转会影响算法的效果)
尺度不变性
旋转不变性
光照不变性
鉴别性强,信息量丰富
实时性不高,因为不断的下采样和插值等操作
对于边缘光滑的目标无法准确提取特征点
主要解决图像配准和目标识别跟踪中下述问题
目标的旋转、缩放、平移
图像的仿射/射影变换
部分减轻光照影响
目标的部分遮挡
杂物场景
1.环境配置问题,之前下载的是vlfeat-0.9.21版本的,代码运行后有错,后来下载了vlfeat-0.9.20版本,将其解压,复制其中的bin文件夹放在项目文件夹下,修改PCV中localdescriptors文件夹中的sift.py(用记事本,或编辑器打开),修改其中 :cmmd = str(r"项目文件夹下的sift.exe路径"+imagname+"--output="+resultname+" "+params),在运行代码就成功了!
2.有些图片Harris角点检测算法检测不出来角点;
3.在进行sift特征点匹配时,大部分图片匹配后的匹配率很低,甚至为零,不知道是照片像素的原因还是相匹配的图片尺寸不同的原因。
4.在进行“地理标志图像”实验时,运行代码报错:ModuleNotFoundError: No module named 'pydot'
解决办法:原因是我还没有安装‘pydot’,在cmd窗口中输入:pip install pydot,出现错误:WARNING: You are using pip version 19.3.1; however, version 20.0.2 is available.You should consider upgrading via the 'python -m pip install --upgrade pip' command. 原因是我当前的pip版本过低,需要更新,当输入:python -m pip install --upgrade pip,后仍出现满屏的红色错误警告,改用国内原下载:python -m pip install --upgrade pip -i https://pypi.douban.com/simple,便可运行。代码运行至一半中断,报错:FileNotFoundError: [WinError 2] "dot" not found in path.这是我还没有下载安装graphviz的原因,解决办法参考博客:https://blog.csdn.net/qq_41784565/article/details/104726166 中“实验问题总结”问题2的解决办法。
参考:
1.https://blog.csdn.net/abcjennifer/article/details/7639681
2.https://www.cnblogs.com/YiXiaoZhou/p/5893835.html