一、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算法python代码实现_深度学习

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, σ) 卷积运算

SIFT算法python代码实现_深度学习_02

2、高斯模糊和高斯金字塔

尺度空间的获取通常使用高斯模糊来实现.I(x,y)表示一幅图像,G(x,y,sigma)为高斯函数,对图像做高斯滤波.

SIFT算法python代码实现_特征点_03

SIFT算法python代码实现_特征点_04

3、关键点检测-DOG

SIFT算法python代码实现_深度学习_05

SIFT算法python代码实现_特征点_06


SIFT算法python代码实现_Image_07

SIFT算法python代码实现_机器学习_08

三、代码实现和结果分析

1.关键点检测

检测图片:

SIFT算法python代码实现_Image_09

代码:

# -*- 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()

结果分析:

SIFT算法python代码实现_特征点_10

对比实图发现边缘点,角点,暗区域的亮点以及亮区域的暗点都被检测并标记出来了

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()

结果分析:

SIFT算法python代码实现_深度学习_11


可以发现对左一进行了特征提取,右一进行了匹配,通过match_twosided()函数返回特征点匹配情况,但是也出现了几处不是特别理想的匹配连线,由上图观察可得,小景深下通过肉眼简单地观察,sift算法仍存在一部分的错误匹配点(右侧天空)

SIFT算法python代码实现_深度学习_12

3.数据集中查找匹配度高的相似图片

待匹配图片:

SIFT算法python代码实现_Image_13


图片集:

SIFT算法python代码实现_Image_14

代码:

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()

结果分析:

SIFT算法python代码实现_深度学习_15

SIFT算法python代码实现_特征点_16


仅选取了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')

结果分析:

SIFT算法python代码实现_Image_17

四、遇到的问题和总结

主要遇到的问题是环境配置

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算法python代码实现_深度学习_18


这样才能开始特征提取了。

关于SIFT的算法理解体会
SIFT算法可帮助定位图像中的局部特征,也就是这些关键点
。这些关键点具有旋转不变量和比例尺的作用,不受图像的大小和方向的影响。就像我们人眼一样我们能轻易的识别同一副图片的不同角度和大小,是因为我们记住了他们的不变特征。同样对于机器来说,如果通过模型训练我觉得计算机也能完成向人一样的高精度识别。因此,虽然对SIFT 的本质理解还不深,但仅从实验结果来看,这算法的功能在图像匹配和物体检测方面有着强势的优点