关于图像匹配的局部描述,我们先来介绍下Harris算法,也称角点检测算法。它的思想是:如果像素周围显示存在多于一个方向的边,我们认为该点为兴趣点,也称角点。但它有缺点,在尺度变化和旋转时匹配效果并不理想。这时SIFT(尺度不变特征变换)被提出了。它是过去十年最成功的图像局部描述子之一。SIFT利用高斯差分很好地解决了Harris的问题,下面介绍SIFT。
(1)兴趣点检测:搜索所有尺度上的图像位置。通过高斯差分函数来识别潜在的对于尺度和旋转不变的兴趣点。D(x,y,e) = ((G(x,y,ke) - G(x,y,e)) * I(x,y) = L(x,y,ke) - L(x,y,e)。兴趣点是在图像位置和尺度变化下D(x, σ ) 的最大值和最小值点。
(2) 关键点定位:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于它们的稳定程度。
(3) 方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而提供对于这些变换的不变性。
(4)关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度被变换成一种表示,这种表示允许比较大的局部形状的变形和光照变化
SIFT特征匹配
构建尺度空间,检测极值点,获得尺度不变性。
特征点过滤并进行精确定位。
为特征点分配方向值。
生成特征描述子。
以特征点为中心取16×16的邻域作为采样窗口,将采样点与特征点的相对方向通过高斯加权后归入包含8个bin的方向直方图,最后获得4×4×8的128维特征描述子。当两幅图像的SIFT特征向量生成以后,下一步就可以采用关键点特征向量的欧式距离来作为两幅图像中关键点的相似性判定度量。取图1的某个关键点,通过遍历找到图像2中的距离最近的两个关键点。在这两个关键点中,如果最近距离除以次近距离小于某个阈值,则判定为一对匹配点。
SIFT流程图
下面是代码具体实现
(1)Harris算子匹配:
`from pylab import *
from PIL import Image
from PCV.localdescriptors import harris
from PCV.tools.imtools import imresize
“”"
This is the Harris point matching example in Figure 2-2.
“”"
#im1 = array(Image.open("…/data/crans_1_small.jpg").convert(“L”))
#im2= array(Image.open("…/data/crans_2_small.jpg").convert(“L”))
im1 = array(Image.open(“01.JPG”).convert(“L”))
im2 = array(Image.open(“02.JPG”).convert(“L”))
im1 = imresize(im1, (int(im1.shape[1]/2), int(im1.shape[0]/2)))
im2 = imresize(im2, (int(im2.shape[1]/2), int(im2.shape[0]/2)))
wid = 5
harrisim = harris.compute_harris_response(im1, 5)
filtered_coords1 = harris.get_harris_points(harrisim, wid+1)
d1 = harris.get_descriptors(im1, filtered_coords1, wid)
harrisim = harris.compute_harris_response(im2, 5)
filtered_coords2 = harris.get_harris_points(harrisim, wid+1)
d2 = harris.get_descriptors(im2, filtered_coords2, wid)
print(‘starting matching’)
matches = harris.match_twosided(d1, d2)
figure()
gray()
harris.plot_matches(im1, im2, filtered_coords1, filtered_coords2, matches)
show()
`
运行结果:
可以看出匹配的效果一般。
(2)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 = ‘01.jpg’
im2f = ‘02.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()
运行结果:
还有就是Harris与SIFT角点检测的比较:
这其中出了一个小插曲,在跑sift时如果没装好vlfeat就会报错:OSError:*.sift not found。这时候我们需要去github下载vlfeat-0.9.20。注意这边是.20版本的,21的跑不了!!!这边给出下载链接:http://www.vlfeat.org/download/。下载解压后打开\bin\win64目录如下:
将sift.exe,vi.dll,vl.lib三个文件复制到pycharm工程目录下。
即把sift.exe的路径放到里面去,同时注意sift.exe后面有一个空格,千万别丢掉!!!。最后点运行就可以得出结果了。
代码:
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 = "C:\\Users\DELL\Desktop\jmu\zs" # set this to the path where you downloaded the panoramio images
path = "C:\\Users\DELL\Desktop\jmu" # 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 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)
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('jmu.png')
图集:
运行结果:
期间因为图片像素超出矩阵维度所以把图片改小了,显示的效果就没那么明显了,其实集美大学中山纪念馆是很漂亮的。下面附些原图宣传下集美大学哈: