Sift算法是David Lowe于1999年提出的局部特征描述子,并于2004年进行了更深入的发展和完善。Sift特征匹配算法可以处理两幅图像之间发生平移、旋转、仿射变换情况下的匹配问题,具有很强的匹配能力。总体来说,Sift算子具有以下特性:
(1)、Sift特征是图像的局部特征,对平移、旋转、尺度缩放、亮度变化、遮挡和噪声等具有良好的不变性,对视觉变化、仿射变换也保持一定程度的稳定性。
(2)、独特性好,信息量丰富,适用于在海量特征数据库中进行快速、准确的匹配。
(3)、多量性,即使少数的几个物体也可以产生大量Sift特征向量。
(4)、速度相对较快,经优化的Sift匹配算法甚至可以达到实时的要求。
(5)、可扩展性强,可以很方便的与其他形式的特征向量进行联合。
作为尺度不变特征变换算法(Sift算法)的加速版,Surf算法在适中的条件下完成两幅图像中物体的匹配基本实现了实时处理,其快速的基础实际上只有一个——积分图像haar求导。我们先来看介绍Sift算法的基本过程,然后再介绍Surf算法。
(1)提取关键点;(2)对关键点附加详细的信息(局部特征)也就是所谓的描述器;(3)通过两方特征点(附带上特征向量的关键点)的两两比较找出相互匹配的若干对特征点,也就建立了景物间的对应关系。提取关键点和对关键点附加详细的信息(局部特征)也就是所谓的描述器可以称做是Sift特征的生成,即从多幅图像中提取对尺度缩放、旋转、亮度变化无关的特征向量,Sift特征的生成一般包括以下几个步骤:
(1)、构建尺度空间,检测极值点,获得尺度不变性;
(2)、特征点过滤并进行精确定位;
(3)、为特征点分配方向值;
(4)、生成特征描述子。
高斯模糊:用来减小图像噪声以及降低细节层次。
DoG(Difference of Gaussian)函数 :在计算上只需相邻高斯平滑后图像相减,用于关键点检测。
# -*- 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 = r'C:\Users\jxtx\计算机视觉\1\1.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(131)
sift.plot_features(im, l1, circle=False)
title(u'SIFT特征',fontproperties=font)
subplot(132)
sift.plot_features(im, l1, circle=True)
title(u'用圆圈表示SIFT特征尺度',fontproperties=font)
# 检测harris角点
harrisim = harris.compute_harris_response(im)
subplot(133)
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()
小结:在同一场景尺度不同,标记的SIFT点在大部分相同,标注的点的位置基本上相同,说明了SIFT算法的局部特征的稳定性。
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 = '../data/sf_view1.jpg'
#…
二维码
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 = '../data/sf_view1.jpg'
# im2f = '../data/sf_view2.jpg'
im1f = r'D:\SiftPicture\1.jpg'
im2f = r'D:\SiftPicture\2.jpg'
# im1f = '../data/climbing_1_small.jpg'
# im2f = '../data/climbing_2_small.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')
figure()
gray()
subplot(121)
sift.plot_features(im1, l1, circle=False)
sift.process_image(im2f, 'out_sift_2.txt')
l2, d2 = sift.read_features_from_file('out_sift_2.txt')
subplot(122)
sift.plot_features(im2, l2, circle=False)
#matches = sift.match(d1, d2)
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)
show()
同一场景的匹配:
小结:在两组图片中,场景相同,只是位置稍微不同,可以看出,匹配度很高,连线很密集,能够很精确的匹配。SIFT算法具有尺度和旋转不变性,即使两张图大小不一样、角度不一致也不会影响匹配结果。
不同场景的匹配
结果:没有匹配出特征点,两个不同场景则无法检测到相似点,说明了SIFT的准确性。
from PIL import Image
from pylab import *
from PCV.localdescriptors import sift
import matplotlib.pyplot as plt # plt 用于显示图片
im1f = 'xinyi1/1.jpg'
im1 = array(Image.open(im1f))
sift.process_image(im1f, 'out_sift_1.txt')
l1, d1 = sift.read_features_from_file('out_sift_1.txt')
arr=[]#单维链表数组
arrHash = {}#字典型数组
for i in range(2,15):
im2f = 'xinyi1/'+str(i)+'.jpg'
im2 = array(Image.open(im2f))
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)
length=len(matches.nonzero()[0])
length=int(length)
arr.append(length)#添加新的值
arrHash[length]=im2f#添加新的值
arr.sort()#数组排序
arr=arr[::-1]#数组反转
arr=arr[:3]#截取数组元素到第3个
i=0
plt.figure(figsize=(6,12))#设置输出图像的大小
for item in arr:
if(arrHash.get(item)!=None):
img=arrHash.get(item)
im1 = array(Image.open(img))
ax=plt.subplot(511 + i)#设置子团位置
ax.set_title('{} matches'.format(item))#设置子图标题
plt.axis('off')#不显示坐标轴
imshow(im1)
i = i + 1
plt.show()
小结:匹配结果准确,可以得出SIFT特征对旋转、尺度缩放、亮度变化等保持不变性,是一种非常稳定的局部特征。
# -*- coding: utf-8 -*-
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 = "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:\SiftPicture" # set this to the path where you downloaded the panoramio images
path = "D:\SiftPicture" # 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) + '.png'
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) + '.png'
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('11.jpg')
小结:图片集用的是我家里的部分场景以及小区建筑。每个场景角度拍摄了多张照片,建筑及场景相似,SIFT算法很精确的匹配出了。在打印机的那张图片中和小区建筑连接起来了,由于打印机的照片场景中拍到了部分建筑,这说明了SIFT算法匹配的准确性,微小的特征都能准确地匹配出来。
RANSAC算法是RANdom SAmple Consensus的缩写,意为随机抽样一致。表面上的意思就是从匹配样本中随机取样,寻找一致的样本点。RANSAC算法是根据一组包含异常数据的样本数据集,计算出数据的数学模型参数,得到有效样本数据的算法。它是在1981年由Fischler和Bolles最先提出。在利用已有算法进行特征点匹配时,常存在的一个问题就是误匹配的问题,这些误匹配的点对匹配的效果产生很大的影响,所以我们需要利用一定的方法剔除误匹配的特征点,在实际应用中,我们常会用到RANSAC算法来消除两两匹配图像的误匹配点,这个算法现在在图像配准以及拼接上得到了广泛的应用。RANSAC算法的核心思想就是在匹配的特征点中随机取4个特征点,通过计算和不断迭代,寻找到最优的参数模型,在这个最优模型中,能匹配上的特征点最多。
# -*- coding: utf-8 -*-
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 = "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 = "F:/dropbox/Dropbox/translation/pcv-notebook/data/panoimages" # set this to the path where you downloaded the panoramio images
path = "F:/dropbox/Dropbox/translation/pcv-notebook/data/panoimages/" # 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) + '.png'
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) + '.png'
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('whitehouse.png')
sift特征匹配(无RANSAC):
sift特征匹配(有RANSAC):
在景深丰富的场景中可以看出匹配出现了十分密集的特征,通过对比实验可以发现,RAMSAC算法剔除错误匹配点的效果较好,在景深丰富场景中,近景产生的匹配点较多。
sift特征匹配(无RANSAC):
sift特征匹配(有RANSAC):
在景深单一的场景中,对比有RANSAC算法剔除错配和无RANSAC算法剔除错配,经过RANSAC算法匹配特征较多,出现了几对明显的错配,如右下方车辆匹配。经RANSAC算法后,错配已大量被剔除,匹配特征减少,说明误差经过RANSAC算法后匹配精确度提高了。
1、SIFT特征是图像的局部特征,其对旋转、尺度缩放、亮度变化保持不变性。
2、sift比Harris角点检测灵活、匹配准确。
3、SIFT有多量性,即使少数的几个物体也可以产生大量的SIFT特征向量。