一、背景
最近需要做一个关于图像识别的算法,应用场景大概就是识别不同的角度,方位的照片中的标志性建筑,也就是图像识别吧,想来想去,大概想了4种方法实现:
1. 基于特征点匹配算法,可以看作是一种图像匹配的问题。只要识别两幅图中的关键点,检测是否有对应点就可以了。
2. 基于图像检索算法,可以看作是一种图像检索的问题。直接调用以图搜图的API,找到相似度最高图像的文字描述,提取关键词就可以。
3. 基于目标检测算法,可以看作是一种目标检测的问题。参考RCNN,SSD等算法的思路,直接进行目标检测即可。
4. 基于目标分类算法,可以看作是一种图像分类的问题。只要我构建足够的库,判断输入图像是否可以被分到库中的某一类别下。
4种算法来说,第三种是代价最高的,需要非常准确的训练数据集,且模型还比较复杂, 所以就pass掉了,第一种方法最简单,第二种方法的准确度依赖于以图搜图的API,第四种方法中规中矩。
本实验先以第一种方法为背景,选取了3张大雁塔的图,其中1张作为真值,另外2张可以看作不同条件下的待检测图,进行特征点匹配算法的图像识别。
二、算法简介
关于特征点匹配算法,最有名的大概就是SIFT——尺度不变特征转换算法。当然后续还有很多新的算法。因此实验选择3个算法:SIFT, SURF, ORB进行实验,网上的介绍也非常多,下面先推荐一些比较好的介绍:
[2]SURF算法
[3]ORB特征提取与匹配
[4]图像特征检测描述(一):SIFT、SURF、ORB、HOG、LBP特征的原理概述及OpenCV代码实现
对于这三种算法,这里只简单的罗列一下操作步骤:
SIFT算法:
1. 特征点检测
2. 伪特征点去除
3. 特征点梯度及方向匹配
4. 特征向量生成
SURF算法:
1. 构建Hessian矩阵,生成特征点
2. 尺度空间构建
3. 特征点定位
4. 特征点主方向匹配
5. 生成特征点描述子
6. 特征点匹配
ORB算法:
1. 方向fast方法的特征点检测
2. Brief算法计算特征点的描述子
3. 特征点匹配
幸运的是,上述三种算法都可以用opencv来实现,而且实现过程也非常简单。
三、算法实现
算法的实现比较简单,网上的参考代码也很多,这里我选择了3张大雁塔的图,目的当然是匹配出不同影像上的大雁塔了,三张图的命名分别为1.jpg,2.jpg,3.jpg,三张图的内容如下所示:
下面直接给出实验代码:
import numpy as np
from matplotlib import pyplot as plt
import cv2
def sift(imgname1, imgname2):
sift = cv2.xfeatures2d.SIFT_create()
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
img1 = cv2.imread(imgname1)
img1 = cv2.resize(img1, (600, 400))
kp1, des1 = sift.detectAndCompute(img1, None) #des是描述子
img2 = cv2.imread(imgname2)
img2 = cv2.resize(img2, (600, 400))
kp2, des2 = sift.detectAndCompute(img2, None)
good = []
for m,n in matches:
if m.distance < 0.70*n.distance:
good.append([m])
img5 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv2.imshow("FLANN", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()
def surf(imgname1, imgname2):
surf = cv2.xfeatures2d.SURF_create()
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params,search_params)
img1 = cv2.imread(imgname1)
img1 = cv2.resize(img1, (600, 400))
kp1, des1 = surf.detectAndCompute(img1,None) #des是描述子
img2 = cv2.imread(imgname2)
img2 = cv2.resize(img2, (600, 400))
kp2, des2 = surf.detectAndCompute(img2,None)
matches = flann.knnMatch(des1,des2,k=2)
good = []
for m,n in matches:
if m.distance < 0.7*n.distance:
good.append([m])
img5 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv2.imshow("SURF", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()
def orb(imgname1, imgname2):
orb = cv2.ORB_create()
img1 = cv2.imread(imgname1)
img1 = cv2.resize(img1, (600, 400))
kp1, des1 = orb.detectAndCompute(img1,None)#des是描述子
img2 = cv2.imread(imgname2)
img2 = cv2.resize(img2, (600, 400))
kp2, des2 = orb.detectAndCompute(img2,None)
# BFMatcher解决匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)
# 调整ratio
good = []
for m,n in matches:
if m.distance < 0.8*n.distance:
good.append([m])
img5 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv2.imshow("ORB", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
imgname1 = '1.jpg'
imgname2 = '2.jpg'
sift(imgname1, imgname2)
surf(imgname1, imgname2)
orb(imgname1, imgname2)
四、实验结果
1. 相近角度下的特征匹配结果
由于1.jpg和2.jpg的角度差距不大,因此先来看看这两张图的匹配效果:
首先是SIFT算法的:
然后是SURF算法:
最后是ORB算法:
2. 不同角度下的特征匹配结果
由于1.jpg和3.jpg的差距比较明显,因此对这两幅图及进行特征匹配:
首先是SIFT算法:
其次是SURF算法:
最后是ORB算法:
五、结论分析
1. 相近角度下,SURF的匹配效果最好,但是仍有很多特征点匹配错误
2. 不同角度下,三种方法的匹配效果都不太好
3. 看过相关文献中,关于这类方法的介绍,说是两幅图的差异小于25%的情况下效果可以,如果差异过大,就不建议使用了