SIFT已经获取专利,所以OpenCV不用调用,我们用ORB来代替SIFT特征,在这篇文章里我们直接谈如何用代码实现。
导入OpenCV库。
import cv2 as cv
在进行特征的提取之前,我们要读入两张图片(图片我就不提供了)。
image1 = cv.imread('1.png')
image2 = cv.imread('2.png')
这里我们使用的是ORB特征,所以要创建一个ORB对象:
# 初始化ORB
orb = cv.ORB_create()
创建之后,就是主要的寻找关键点和计算描述子:
# 寻找关键点
kp1 = orb.detect(img1)
kp2 = orb.detect(img2)
# 计算描述符
kp1, des1 = orb.compute(img1, kp1) # 计算哪张图片的用哪张图片的关键点。
kp2, des2 = orb.compute(img2, kp2)
找到了关键点可以画出关键点看一看:
# 画出关键点
outimg1 = cv.drawKeypoints(img1, keypoints=kp1, outImage=None)
outimg2 = cv.drawKeypoints(img2, keypoints=kp2, outImage=None)
# 这里是把两张图片在同一个窗口中显示。
import numpy as np
outimg3 = np.hstack([outimg1, outimg2])
cv.imshow("Key Points", outimg3)
cv.waitKey(0)
显示出来的关键点结果:
有了关键点和描述子,我们就要对这些点进行匹配。这里我们用的是Brute-Force匹配器,它获取第一组中一个特征的描述符,并通过一些距离计算与第二组中的所有其他特征匹配,最接近的一个被返回。
我们用Hamming距离对描述子进行匹配。
# 初始化 BFMatcher
bf = cv.BFMatcher(cv.NORM_HAMMING)
# 对描述子进行匹配
matches = bf.match(des1, des2)
# 计算最大距离和最小距离
min_distance = matches[0].distance
max_distance = matches[0].distance
for x in matches:
if x.distance < min_distance:
min_distance = x.distance
if x.distance > max_distance:
max_distance = x.distance
'''
当描述子之间的距离大于两倍的最小距离时,认为匹配有误。
但有时候最小距离会非常小,所以设置一个经验值30作为下限。
'''
good_match = []
for x in matches:
if x.distance <= max(2 * min_distance, 30):
good_match.append(x)
这里我们将绘制结果单独拿出来:
draw_match(img1, img2, kp1, kp2, good_match)
def draw_match(img1, img2, kp1, kp2, match):
outimage = cv.drawMatches(img1, kp1, img2, kp2, match, outImg=None)
cv.imshow("Match Result", outimage)
cv.waitKey(0)
显示出来的结果:
import cv2 as cv
def ORB_Feature(img1, img2):
# 初始化ORB
orb = cv.ORB_create()
# 寻找关键点
kp1 = orb.detect(img1)
kp2 = orb.detect(img2)
# 计算描述符
kp1, des1 = orb.compute(img1, kp1)
kp2, des2 = orb.compute(img2, kp2)
# 画出关键点
outimg1 = cv.drawKeypoints(img1, keypoints=kp1, outImage=None)
outimg2 = cv.drawKeypoints(img2, keypoints=kp2, outImage=None)
# 显示关键点
# import numpy as np
# outimg3 = np.hstack([outimg1, outimg2])
# cv.imshow("Key Points", outimg3)
# cv.waitKey(0)
# 初始化 BFMatcher
bf = cv.BFMatcher(cv.NORM_HAMMING)
# 对描述子进行匹配
matches = bf.match(des1, des2)
# 计算最大距离和最小距离
min_distance = matches[0].distance
max_distance = matches[0].distance
for x in matches:
if x.distance < min_distance:
min_distance = x.distance
if x.distance > max_distance:
max_distance = x.distance
# 筛选匹配点
'''
当描述子之间的距离大于两倍的最小距离时,认为匹配有误。
但有时候最小距离会非常小,所以设置一个经验值30作为下限。
'''
good_match = []
for x in matches:
if x.distance <= max(2 * min_distance, 30):
good_match.append(x)
# 绘制匹配结果
draw_match(img1, img2, kp1, kp2, good_match)
def draw_match(img1, img2, kp1, kp2, match):
outimage = cv.drawMatches(img1, kp1, img2, kp2, match, outImg=None)
cv.imshow("Match Result", outimage)
cv.waitKey(0)
if __name__ == '__main__':
# 读取图片
image1 = cv.imread('1.png')
image2 = cv.imread('2.png')
ORB_Feature(image1, image2)
参考文献:
OpenCV-Python官方文档.