一、SIFT算法
1、算法介绍
SIFT的全称是Scale Invariant Feature Transform,首次由D. G.
Lowe于2004年以《Distinctive Image Features from Scale-Invariant
Keypoints[J]》发表于IJCV中。SIFT算法的实质是在不同的尺度空间上查找关键点,计算关键点的大小、方向、尺度信息,利用这些信息组成关键点对特征点进行描述。
SIFT所查找的关键点都是一些十分突出,不会因光照,仿射便函和噪声等因素而变换的“稳定”特征点,如角点、边缘点、暗区的亮点以及亮区的暗点等。匹配的过程就是对比这些特征点的过程。
因而SIFT算法可以用来解决的问题
• 目标的旋转、缩放、平移(RST)
• 图像仿射/投影变换(视点viewpoint)
• 弱光照影响(illumination)
• 部分目标遮挡(occlusion)
• 杂物场景(clutter)
• 噪声
2、算法步骤
该算法的实质可以归为不同尺度空间上寻找特征点(关键点)的问题
SIFT算法实现特征匹配主要有三个流程:
1、提取关键点;
2、对关键点附加详细的信息(局部特征),即描述符;
3、通过特征点(附带上特征向量的关键点)的两两比较找出相互匹配的若干对特征点,建立景物间的对应关系。
二、相关概念和背后的数学原理
问题引出:SIFT寻找的是哪些点,这些点有什么特征?
这些点是一些十分突出的点不会因光照、尺度、旋转等因素的改变而消 失,比如角点、边缘点、暗区域的亮点以及亮区域的暗点。既然两幅图像中 有相同的景物,那么使用某种方法分别提取各自的稳定点,这些点之间会有 相互对应的匹配点。
1、尺度空间
尺度空间理论最早于1962年提出,其主要思想是通过对原始图像进行尺度变换,获得图像多尺度下的空间表示。从而实现边缘、角点检测和不同分辨率上的特征提取,以满足特征点的尺度不变性。尺度空间中各尺度图像的 模糊程度逐渐变大,能够模拟 人在距离目标由近到远时目标 在视网膜上的形成过程。 尺度越大图像越模糊。
根据文献《Scale-space theory: A basic tool for analysing structures at different scales》可知,高斯核是唯一可以产生 多尺度空间的核,一个 图像的尺度空间,L(x, y, σ) ,定义为原始图像 I(x, y)与一个可变尺度的2 维高斯函数G(x, y, σ) 卷积运算
2、高斯模糊和高斯金字塔
尺度空间的获取通常使用高斯模糊来实现.I(x,y)表示一幅图像,G(x,y,sigma)为高斯函数,对图像做高斯滤波.
3、关键点检测-DOG
三、代码实现和结果分析
1.关键点检测
检测图片:
代码:
# -*- coding: utf-8 -*-
from PCV.localdescriptors import harris
from PCV.localdescriptors import sift
from PIL import Image
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
from pylab import *
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
imname = 'D:\PhotoTest/test1.png'
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)
show()
结果分析:
对比实图发现边缘点,角点,暗区域的亮点以及亮区域的暗点都被检测并标记出来了
2.描述子匹配
测试图:
代码:
```python
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:\PhotoTest\\test1.jpg'
im2f = 'D:\PhotoTest\\test3.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()
结果分析:
可以发现对左一进行了特征提取,右一进行了匹配,通过match_twosided()函数返回特征点匹配情况,但是也出现了几处不是特别理想的匹配连线,由上图观察可得,小景深下通过肉眼简单地观察,sift算法仍存在一部分的错误匹配点(右侧天空)
3.数据集中查找匹配度高的相似图片
待匹配图片:
图片集:
代码:
from PIL import Image
from pylab import *
from PCV.localdescriptors import sift
import matplotlib.pyplot as plt # plt 用于显示图片
im1f = 'D:\PhotoTest\\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,5):
im2f = 'D:\PhotoTest\\'+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[:5]#截取数组元素到第五个
i=0
plt.figure(figsize=(5,12))#设置输出图像的大小/002/2.jpg
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()
结果分析:
仅选取了4张范围2~5.jpg的图片,图2做视角的改变,图3做光照改变测试
可以发现SIFT算法在视角的改变,光照的改变和尺度的改变的条件下依旧能够完成较高精度的匹配
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 = "D:\PhotoTest" # set this to the path where you downloaded the panoramio images
path = "D:\PhotoTest" # 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')
结果分析:
四、遇到的问题和总结
主要遇到的问题是环境配置
1.pcv的配置
本来想直接在控制台cmd使用命令"pip install pcv"结果找不到这个库。
通过https://github.com/jesolem/PCV下载安装包下载后解压得到文件夹PCV-master,通过cmd进入setup.py所在的目录执行命令“python setup.py install ”才算是完成了PCV的安装
2.接下来爆出第二个问题:vlfeat配置
由于出现问题 tmp.pgm转empire.sift失败,发现是vlfeat配置出了问题,找到PCV文件夹的ift.py文件,打开找到cmmd更改了路径:
这样才能开始特征提取了。
关于SIFT的算法理解体会:
SIFT算法可帮助定位图像中的局部特征,也就是这些关键点
。这些关键点具有旋转不变量和比例尺的作用,不受图像的大小和方向的影响。就像我们人眼一样我们能轻易的识别同一副图片的不同角度和大小,是因为我们记住了他们的不变特征。同样对于机器来说,如果通过模型训练我觉得计算机也能完成向人一样的高精度识别。因此,虽然对SIFT 的本质理解还不深,但仅从实验结果来看,这算法的功能在图像匹配和物体检测方面有着强势的优点