OpenCV sift特征匹配通过提取两张图片的sift特征点,匹配后计算单应矩阵(该部分为SLAM相关知识,想了解的同学可以学习《视觉SLAM十四讲从入门到实践》【高翔】视觉SLAM十四讲_哔哩哔哩_bilibili)
以下为OpenCV sift代码demo:
opencv-python:4.8.1.78
opencv-contrib-python:4.8.1.78
numpy:1.24.3
import cv2
import numpy as np
def sift(img, map, ratio, Min_MatchCount):
map = cv2.resize(map, (5472, int(map.shape[0] / map.shape[1] * 5472)))
h1, w1 = img.shape[:2]
h2, w2 = map.shape[:2]
sift = cv2.SIFT().create()
kp1, des1 = sift.detectAndCompute(img, None)
kp2, des2 = sift.detectAndCompute(map, None)
# 采用FLANN匹配算法
# FLANN_INDEX_KDTREE = 1
# index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
# search_params = dict(checks=50)
# flann = cv2.FlannBasedMatcher(index_params, search_params)
# matches = flann.knnMatch(des1, des2, k=2)
# 这里采用BF暴力匹配!
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
good = []
for m,n in matches:
if m.distance < ratio * n.distance:
good.append(m)
if len(good) > Min_MatchCount:
src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
matchesMask = mask.ravel().tolist()
pts = np.float32([[0, 0], [0, h1-1], [w1-1, h1-1], [w1-1, 0]]).reshape(-1, 1, 2)
dst = cv2.perspectiveTransform(pts, M)
map = cv2.polylines(map, [np.int32(dst)], True, (0,255,0),
3, lineType=cv2.LINE_AA)
draw_params = dict(matchColor=(0,255,0),
singlePointColor = None,
matchesMask = matchesMask,
flags=2)
result = cv2.drawMatches(img, kp1, map, kp2, good, None, **draw_params)
cv2.imwrite("result.jpg", result)
return M
else:
print("Not enough key-points pair")
return None
if __name__ == "__main__":
img1 = cv2.imread("filepath")
img2 = cv2.imread("filepath")
M = sift(img1, img2, 0.75, 8)
print(f"homography for img1 and img2:{M}")
常见问题:
1. 报错:error: (-215) trainDescCollection[iIdx].rows < IMGIDX_ONE
解决方法:匹配点过多,对匹配的图片进行resize,通过测试选择适合的resize大小。
(如有其他报错可在评论区评论,看到回复~)