SIFT算法-图像特征匹配、地理标记图像匹配

1.SIFT简介

1999年David G.Lowe教授总结了基于特征不变技术的检测方法,在图像尺度空间基础上,提出了对图像缩放、旋转保持不变性的图像局部特征描述算子一SIFT(尺度不变特征变换),该算法在2004年完善。

1.1 SIFT算法实现特征匹配主要流程

SIFT算法实现特征匹配主要有三个流程:

  • 提取关键点;
  • 对关键点附加详细的信息(局部特征),即描述符;
  • 通过特征点(附带上特征向量的关键点)的两两比较找出相互匹配的若干对特征点,建立景物间的对应关系。

1.2 SIFT算法可以解决的问题

  • 目标的旋转、缩放、平移(RST)
  • 图像仿射/投影变换(视点viewpoint)
  • 弱光照影响( illumination)目标的旋转、缩放、平移(RST)
  • 图像仿射/投影变换(视点viewpoint)
  • 弱光照影响( illumination)
  • 噪声

2.SIFT描述子

2.1检测感兴趣点

2.2.1开源工具包VLFeat安装

为了计算图像的SIFT特征,我们用开源工具包VLFeat。VLFeat可以在www.vlfeat.org.上下载,它的二进制文件可以用于一些主要的平台。这个库是用C写的,不过我们可以利用它的命令行接口。此外,它还有Matlab接口。
VLFeat的安装可以参考此链接VLFeat的安装.
需要注意的是:

  1. VLFeat现在更新到0.9.21版本,但部分 身边的很多电脑(包括我自己)都无法使用最新版本,可以更换0.9.20版本,即可顺利使用。
    使用0.9.21版本的报错信息

  2. 更换sift.py cmmd路径时不要忘了保留空格将cmmd中的目录修改为你自己放置的Vlfeat bin所在目录

代码:
# -*- coding=utf-8 -*-
# name: nan chen
# date: 2021/3/23 13:03
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 = 'D:\image\jmu005.jpg'
im = array(Image.open(imname).convert('L'))
sift.process_image(imname, 'jmu.sift')
l1, d1 = sift.read_features_from_file('jmu.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], 'b.')
axis('off')
title(u'Harris角点', fontproperties=font)

show()
运行结果:

集美大学尚大楼
集美大学尚大楼
集美大学尚大楼
集美大学尚大楼
由上图可以清楚的看出,两种检测兴趣点的算法检测出的兴趣点并不相同。SIFT检测出的特征点明显要多于Harris角点检测出的点。

2.2描述子匹配

代码:
# -*- coding=utf-8 -*-
# name: nan chen
# date: 2021/3/23 20:43
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:\image\jmu005.jpg'
    im2f = 'D:\image\jmu007.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匹配结果:
在这里插入图片描述

Harris角点匹配结果:
在这里插入图片描述
由上面两种不同方法对同样一组图像的匹配结果可以看出,Harris算法在特征点匹配中有许多错配的,而SIFT算法能检测出更多的特征点,且匹配的更加正确。这是因为SIFT算法具有尺度不变性和旋转不变性,即使两张图片的大小角度有些许不同,也不影响匹配的结果。而Harris算法不具有尺度不变性,对尺度变化十分敏感,当尺度变化时,许多正确的特征点无法被正确检测。

2.2.1匹配同一幅图像不同分辨率的 SIFT 特征

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
由上面的图片可以看出,SIFT算法具有良好的尺度不变性,图像进行缩小变大后图像依旧可以很好的进行匹配。

2.2.1匹配同一景物不同角度的 SIFT 特征

集美大学嘉庚图书馆
集美大学嘉庚图书馆

由上面的图片可以看出,嘉庚图书馆不同角度,仍可以进行较好的SIFT特征匹配。

注意事项:

所要匹配的图像需要调整成一致的大小,否则会报错
报错信息

3.地理标记图像匹配

3.1地理图像采集

拍摄了学校尚大楼及嘉庚图书馆在不同光线,不同角度的照片,将使用这些图片,利用局部特征对其进行匹配。照片集如下:
图片摄于集美大学

3.2安装配置Graphviz和pydot

我们要对匹配后的图像进行连接可视化,在一个图中用边线表示它们之间是相连的。pydot工具包提供了GraphViz graphing库的Python接口,可以实现连接可视化。
该工具包要需要用到GraphViz,我们先安装GraphViz。到官网graphviz.gitlab.io下载安装即可,在安装时最好勾选自动添加环境变量,就不用手动配置环境变量。如若忘记勾选还要找到安装路径文件夹,找到dot文件,将它的路径添加到系统环境变量path中。成功安装后在命令行输入dot -version,查看graphviz是否安装成功。
成功安装
然后直接在命令行使用pip安装相应工具包。

代码

pip install graphviz
pip install pydot

成功安装后便可运行代码了。

# -*- coding=utf-8 -*-
# name: nan chen
# date: 2021/3/23 21:43
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:\\image\\"  # set this to the path where you downloaded the panoramio images
path = "D:\\image\\"  # 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('jmu.png')


运行结果:

产生的matchscores矩阵:
在这里插入图片描述
可视化结果:
匹配结果

结果分析:

由上图可以看到两组图像,第一组为嘉庚图书馆不同视角的图像,第二组为学校尚大楼不同视角的图像。利用局部描述子对学校不同场景进行了匹配。
共选取了20张图片其中包括了4张嘉庚图书馆,16张尚大楼的图片,共有16张图片成功匹配。其中3张在晚上拍的尚大楼照片及尚大楼正面的照片无法成功匹配。
在这里插入图片描述
可以看到我们将创建链接所需的最小匹配数设为2,两两图像进行特征匹配后的匹配数若大于2,将进行可视化的链接。
另外几张尚大楼的照片由于光线与角度与其它照片相差过多,导致目标的特征点消失,所求得的匹配数为0,以至于没有被匹配。
由于放了20张图片且电脑性能不是很好,按照图像原图匹配的速度实在过慢,便将尚大楼图片统一调整成1090*1090大小后,运行速度快了许多,但是由于图片压缩也导致了精确度没有原图高的问题。
由上述实验可以看出SIFT不但对于旋转、尺度缩放保持不变性,而且对视角变化、噪声也保持一定程度的稳定性,与Harris算法相比,有很大的改进。
在这里插入图片描述

也可以看出,SIFT算法也有需要改进的地方,光线、角度相差过大,或者是远近相差过大时,不能进行很好的匹配,不能处理很强的旋转不变性问题。且若两张图有十分相像的地方,也可能导致错配。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值