图像特征点匹配
图像特征点匹配
ytkz本文主要介绍图像特征点匹配众多方法中的sift算法。这是几年前写的代码,现在再回看发现很多内容我不记得了,记忆被删除了一样。但是,当时记录好了,也把代码、数据备份了,现在一边运行、一边查资料,很快就把这段代码捡起来了。话不多说,直接进入今天主题。
航片拼接、点云生成、SFM不可绕过的是特征点匹配。而特征点匹配中最经典、有效、稳定的方法是sift算法。我们有必要去学习一下这个sift算法。
下面是一个利用python语言调用opencv中的算法的示例。
输入图像1:
输入图像2:
具体代码如下:
# -*- coding: utf-8 -*-
# @Time : 2021/3/10 20:11
import numpy as np
import cv2
'''
sift practice code 1
'''
class SIFT():
def img_sift(self, file1, file2):
sift = cv2.xfeatures2d.SIFT_create()
img1 = cv2.imread(file1)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) # 灰度处理图像
img2 = cv2.imread(file2)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 灰度处理图像
data1 = self.match_2d(gray1, gray2)
gray1 = data1[:, :, 0] / 255
gray2 = data1[:, :, 1] / 255
hmerge = np.hstack((gray1, gray2)) # 水平拼接
cv2.imshow("gray", hmerge) # 拼接显示为gray
cv2.waitKey(0)
data2 = self.match_3d(img1, img2)
img1 = np.array(data2[:, :, :, 0]).astype('uint8')
img2 = np.array(data2[:, :, :, 1]).astype('uint8')
kp1, des1 = sift.detectAndCompute(img1, None) # des是描述子
kp2, des2 = sift.detectAndCompute(img2, None) # des是描述子
img3 = cv2.drawKeypoints(img1, kp1, img1, color=(255, 0, 255)) # 画出特征点,并显示为红色圆圈
img4 = cv2.drawKeypoints(img2, kp2, img2, color=(255, 0, 255)) # 画出特征点,并显示为红色圆圈
hmerge = np.hstack((img3, img4)) # 水平拼接
cv2.imshow("point", hmerge) # 拼接显示为gray
cv2.waitKey(0)
# BFMatcher解决匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
# 调整ratio
good = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good.append([m])
img5 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags=2)
cv2.imshow("BFmatch", img5)
cv2.waitKey(0)
cv2.destroyAllWindows()
def match_2d(self, d1, d2):
x1, y1 = np.shape(d1)
x2, y2 = np.shape(d2)
if x1 > x2 and y1 > y2:
d3 = np.zeros((x1, y1))
d3[d3 == 0] = 255
d3[5:5 + x2, 5:5 + y2] = d2
x3, y3 = np.shape(d3)
else:
if y1 < y2:
d3 = np.zeros((x2, y2))
d3[d3 == 0] = 255
d3[5:5 + x1, 5:5 + y1] = d1
x3, y3 = np.shape(d3)
d = []
x3, y3 = np.shape(d3)
datagray = np.zeros(shape=(x3, y3, 2))
datagray[:, :, 0] = d3
if x3 == x1:
datagray[:, :, 1] = d1
elif x3 == x2:
datagray[:, :, 1] = d2
return datagray
def match_3d(self, d1, d2):
x1, y1, z1 = np.shape(d1)
x2, y2, z2 = np.shape(d2)
if x1 > x2 and y1 > y2:
d3 = np.zeros((x1, y1, 3))
for i in range(z1):
print(i)
d3[5:5 + x2, 5:5 + y2, i] = d2[:, :, i]
else:
if y1 < y2:
d3 = np.zeros((x2, y2, 3))
for i in range(z1):
d3[5:5 + x1, 5:5 + y1,i] = d1[:, :, i]
d=[]
x3, y3, z3 = np.shape(d3)
datagray = np.zeros(shape=(x3, y3, z3, 2))
datagray[:, :, :, 0] = d3
if x3 == x1:
datagray[:, :, :, 1] = d1
elif x3 == x2:
datagray[:, :, :, 1] = d2
return datagray
if __name__ == '__main__':
imgname2 = r'.\1.jpg'
imgname1 = r'.\2.jpg'
a = SIFT()
a.img_sift(imgname1, imgname2)
图像1和图像2的尺寸不一样,match_3d函数的目的是为了让这两张图像的尺寸一样。
尺寸一样才能顺利地进行可视化。小图使用零值进行填充,最终小图的尺寸与大图保持一种。实际上,在图像特征点匹配中不需要对图像进行尺寸一致处理,这样的处理只是为了图像可视化而已。
代码中结果可视化如下,零值在图像中显示为黑色。
下一步就是查找特征点,通过opencv的sift算法,我们轻松找到这两幅图像的特征点,可视化结果如下:
此时,特征点是无序的,需要给它们配对起来。下一步是特征点匹配。
每个特征点是128维的向量,目标的识别是通过两点集内特征点描述子的比对来完成。具有128维的特征点描述子的相似性度量采用欧式距离。
特征点匹配结果如下:
以上具体操作请看代码,在运行代码的时候,多打断点,多debug,多查看变量的数据结构。