2021-03-28
作者:互联网
[计算机视觉]匹配地理标记图像
一、sift原理
SIFT算法概述
尺度不变特征转换即SIFT (Scale-invariant feature transform)是一种计算机视觉的算法。它用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在1999年所发表,2004年完善总结。 其应用范围包含物体辨识、机器人地图感知与导航、影像缝合、3D模型建立、手势辨识、影像追踪和动作比对。SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。
Sfit特征提取和匹配具体步骤
-
生成高斯差分金字塔(DOG金字塔),尺度空间构建
-
空间极值点检测(关键点的初步查探)
-
稳定关键点的精确定位
-
关键点描述
-
特征点匹配
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
**
生成高斯差分金字塔(DOG金字塔),尺度空间构建
**
主要思想是通过对原始图像进行尺度变换,获得图像多尺度下的尺度空间表示序列,对这些序列进行尺度空间主轮廓的提取,并以该主轮廓作为一种特征向量,实现边缘、角点检测不同分辨率上的关键点提取等。
各尺度下图像的模糊度逐渐变大,能够模拟人在距离目标由近到远时目标物体在视网膜上的形成过程。
为了在尺度空间中找到稳定不变的极值点,在SIFT算法中使用了高斯差分(DOG)函数D(x,y,σ)D(x,y,σ),定义为
D(x,y,σ)=[G(x,y,kσ)−G(x,y,σ)]∗I(x,y)
=L(x,y,kσ)−L(x,y,σ)
其中 kσkσ和 σσ是连续的两个图像的平滑尺度,所得到的差分图像再高斯差分金字塔中
高斯模糊——降低图像中的噪点,强调了图像的重要特征。进行高斯模糊之和,纹理和次要细节将从图像中删除,并且保留形状和边缘之类的相关信息。
实现DOG——初始图像与不同σ值的高斯函数卷积,得到一垛模糊后图像,然后将这一垛图像临近两两相减得到对应的DOG。一副图像可以产生几组图像,一组图像包括几层图像。s为每组层数一般为3~5层,最后可以将s和k的关系确立为k=2^(1/s)
**尺度空间检测极值点
**——DOG上某个像素要和本尺度的8个像素以及上下相邻尺度各9个相邻像素共26个像素值进行比较,以确定是否为局部最大或最小值。如果它是相邻像素中最高或者最低的像素,则确定该像素点是尺度空间的极值点之一。
*稳定关键点的精确定位
DOG值对噪声和边缘比较敏感,所以在第2步的尺度空间中检测到的局部极值点还要经过进一步的筛选,去除不稳定和错误检测出的极值点,另一点就是在构建高斯金字塔过程中采用了下采样的图像,在下采样图像中提取的极值点对应在原始图像中的确切位置,也是要在本步骤中解决的问题。
关键点描述*
兴趣点(关键点)位置描述子给出兴趣点的位置 和尺度信息,为了实现旋转不变性,基于每个点周围图像梯度的方向和大小,sift描述算子使用主方向描述参考方向,主方向使用直方图来衡量。sift描述算子在每个像素点附近选取子区域网格,在每个子区域计算图像梯度方向直方图,拼接起来组成描述算子向量。sift描述算子是由44个子区域,每个子区域有8个方向,会产生128个小区间直方图(448=128)也就是一张图像的每一个像素点都有128维的特征向量来唯一标识,即使方向有变换,也可以通过主方向来同步变换达到旋转不变性。
David G.Lowed的实验结果表明:对每个关键点,采用44*8共128维向量的描述子进项关键点表征,综合效果最佳:
特征点匹配
分别对模板图(参考图)和实时图(观测图)建立关键点描述子集合。目标的识别是通过两点集内关键点描述子的比对来完成具有128维的关键点描述子的相似性度量采用欧式距离。
sift特征点提取和匹配
```python
from pylab import *
from PIL import Image
from numpy import *
import os
def 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("sift " + 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*pi
x = 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')
return
def 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.6
desc1_size = desc1.shape
matchscores = 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 matchscores
def 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] = 0
return matches_12
def 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)
def plot_matches(im1, im2, locs1, locs2, matchscores, show_below=True):
"""显示一幅带有连接匹配之间连线的图片
输入:im1,im2(数组图像),locs1,locs2(特征位置),matchscores(match的输出),
show_below(如果图像应该显示再匹配下方)"""
im3 = appendimages(im1,im2)
if show_below:
im3 = vstack((im3,im3))
imshow(im3)
cols1 = im1.shape[1]
for i in range(len(matchscores)):
if matchscores[i] > 0:
plot([locs1[i, 0], locs2[matchscores[i, 0], 0] + cols1], [locs1[i, 1], locs2[matchscores[i, 0], 1]], 'c')
axis('off')
if __name__ == '__main__':
# imname = 'xqimage08.jpg'
# im1 = array(Image.open(imname).convert('L'))
# process_image(imname, 'xqimage08.sift')
# l1, d1 = read_features_from_file('xqimage08.sift')
#
# figure()
# gray()
# plot_features(im1, l1, circle=True)
# show()
im1f = r'p1.jpg'
im2f = r'p6.jpg'
im1 = array(Image.open(im1f))
im2 = array(Image.open(im2f))
process_image(im1f, 'jimei-sift2.sift')
l1, d1 = read_features_from_file('jimei-sift2.sift')
figure()
gray()
subplot(121)
plot_features(im1, l1, circle=False)
process_image(im2f, 'jimei-sift2.sift')
l2, d2 = read_features_from_file('jimei-sift2.sift')
subplot(122)
plot_features(im2, l2, circle=False)
matches = match_twosided(d1, d2)
print('{} matches'.format(len(matches.nonzero()[0])))
figure()
gray()
plot_matches(im1, im2, l1, l2, matches, show_below=True)
show()
原图:
p1:
p2:
结果截图:
得到的结论;
发现sift更适用于图像特征检测,旋转不变性较强、可以解决一些光线和亮度问题,且比harris灵活、匹配准确些。虽然sift算法能够解决旋转角度、光线亮度问题,但是也不是十分准确,对于旋转角度过大和光线亮度反差很大时,也会出现错误点匹配(甚至会出现找不到特征点),从图中匹配的结果看出来sift算法对旋转角度匹配点也不是很多。
标签:03,matches,28,im1,sift,im2,2021,图像,关键点 来源: https://blog.csdn.net/weixin_43423030/article/details/115284136