在Python OpenCV2中获取特征匹配点索引的问题排查
图像特征匹配后有效匹配点索引提取问题
使用ORB特征检测器、BF-Hamming匹配器完成图像特征匹配,通过RANSAC算法筛选有效匹配点后,尝试提取两张图像上特征匹配点的索引,但绘制结果与预期不符。
完整实现代码
import cv2, numpy as np img1 = cv2.imread('img1.jpg') img2 = cv2.imread('img2.jpg') gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # ORB特征检测 + BF-Hamming匹配 detector = cv2.ORB_create() kp1, desc1 = detector.detectAndCompute(gray1, None) kp2, desc2 = detector.detectAndCompute(gray2, None) matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) matches = matcher.match(desc1, desc2) # 按匹配距离排序 matches = sorted(matches, key=lambda x:x.distance) # 绘制所有匹配点 res1 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) # RANSAC筛选有效匹配点并计算单应矩阵 src_pts = np.float32([ kp1[m.queryIdx].pt for m in matches ]) dst_pts = np.float32([ kp2[m.trainIdx].pt for m in matches ]) mtrx, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) h,w = img1.shape[:2] pts = np.float32([ [[0,0]],[[0,h-1]],[[w-1,h-1]],[[w-1,0]] ]) dst = cv2.perspectiveTransform(pts,mtrx) # 绘制RANSAC筛选后的有效匹配点 matchesMask = mask.ravel().tolist() res2 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ matchesMask = matchesMask, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) # 计算匹配准确率 accuracy=float(mask.sum()) / mask.size print("accuracy: %d/%d(%.2f%%)"% (mask.sum(), mask.size, accuracy)) # 显示结果 from google.colab.patches import cv2_imshow cv2_imshow(res2) cv2.waitKey() cv2.destroyAllWindows()
用户尝试的提取代码
print(matchesMask) kp2_test = [] i = 0 while i < len(matchesMask): if matchesMask[i] == 1: kp2_test.append(kp2[i]) i = i + 1 kp2_test2 = [] kp2_test2.append(kp2_test) print(len(kp2_test)) print(kp2_test)
test2 = cv2.drawKeypoints(img2, kp2_test, img1, (0,255,0),flags =0) cv2_imshow(test2) cv2.waitKey() cv2.destroyAllWindows()
问题原因与修正方案
错误原因
用户直接用matchesMask的索引i去取kp2[i],这个逻辑存在错误:
matchesMask的索引i对应的是第i个匹配对(即matches[i])- 每个匹配对
matches[i]中,trainIdx才是该匹配点在kp2列表中的正确索引,而非i本身 - 直接用
kp2[i]会取到和当前匹配对无关的关键点,导致绘制结果与预期不符
修正后的代码
# 提取图像1的有效匹配关键点 valid_kp1 = [kp1[m.queryIdx] for m, is_valid in zip(matches, matchesMask) if is_valid == 1] # 提取图像2的有效匹配关键点 valid_kp2 = [kp2[m.trainIdx] for m, is_valid in zip(matches, matchesMask) if is_valid == 1] # 绘制图像2上的有效匹配点(第三个参数传None,避免覆盖原图像) test2 = cv2.drawKeypoints(img2, valid_kp2, None, (0,255,0), flags=0) cv2_imshow(test2) # 如果需要提取两张图的匹配点索引,可使用以下代码: valid_kp1_indices = [m.queryIdx for m, is_valid in zip(matches, matchesMask) if is_valid == 1] valid_kp2_indices = [m.trainIdx for m, is_valid in zip(matches, matchesMask) if is_valid == 1] print("图像1有效匹配点索引:", valid_kp1_indices) print("图像2有效匹配点索引:", valid_kp2_indices)
说明
- 用
zip(matches, matchesMask)同时遍历匹配对和对应的有效性标记 - 对每个有效匹配(
is_valid == 1),通过m.queryIdx获取图像1的关键点索引,m.trainIdx获取图像2的关键点索引 - 绘制关键点时,
drawKeypoints的第三个参数传None,会自动创建新图像绘制,避免和原图像混合导致混乱
内容的提问来源于stack exchange,提问作者DAEHYUN KIM
相关产品推荐
相关产品推荐

