前一段时间做了个项目,就此记录下遇到的坑。网上查了很多资料,求图片在三维中的旋转角度,要么vip才能看或者收费,要么文章就是写的乱七八糟的,要么根本没写角度怎么计算的。索性我自己写吧。
转载请注明出处https://blog.youkuaiyun.com/qq_38284951/article/details/113335656
通常大佬们的增强现实使用的是slam技术,但是本人是个slam小白不懂那一套,于是通过各种渠道、资料,先去了解如何实现以图识图,以图识图很好做,有传统方法和深度学习方法。
但是为了省去以后添加一张新的识别图而重新训练的尴尬,采用了传统的opencv中自带的提取特征方法,并通过这些特征点去匹配,匹配方法有暴力匹配有flann方法,并通过匹配点
找到待识别图和原图之间的单应性矩阵的关系。具体就不详细介绍了,网上关于这些方法的介绍和详细代码一大堆,包括性能等等,我就直接上相关代码。我这里使用过orb、sift、brisk以及akaze。
sift,orb和brisk相关代码 返回单应性矩阵和匹配点,brisk, akaze是什么匹配方法我记不清了,读者可以分别进行测试下。我用了网上的一张图片进行了旋转后和原图做测试,可以看到sift的匹配效果。
import cv2
import numpy as np
from matplotlib import pyplot as plt
def sift(img1,img2):
sift = cv2.xfeatures2d.SIFT_create(nfeatures=100)#特征点数可以自行查阅opencv
# brisk = cv2.BRISK_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
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)
#筛选好的特征点
good = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good.append(m)
# 只有好的匹配点多于 10 个才查找目标,否则显示匹配不足
if len(good) > 10:
# 获取匹配点在原图像和目标图像中的的位置
# kp1 :原图像的特征点
# m.queryIdx :匹配点在原图像特征点中的索引
# .pt :特征点的坐标
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)
# 获取变换矩阵,采用 RANSAC 算法
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 4.0)
print("mask", len(mask))
matchesMask = mask.ravel().tolist()
else:
print("Not enough matches are found ",len(matches))
matchesMask = None
draw_params = dict(matchColor=(0, 0, 255), # draw matches in green color
singlePointColor=None,
matchesMask=matchesMask, # draw only inliers
flags=2)
img3 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params)
plt.imshow(img3), plt.title('Test3'),
plt.axis('off')
plt.show()
return src_pts,M
if __name__ == '__main__':
img_1 = r"E:\workspace\yolo5\yoloV5-arcface_forlearn-master\yoloV5_arcface\inference\images\02.jpg"
img_2 = r"E:\workspace\yolo5\yoloV5-arcface_forlearn-master\yoloV5_arcface\inference\images\03.jpg"
img1 = cv2.imread(img_1,0)
img2 = cv2.imread(img_2,0)
sift(img1,img2)
orb相关代码,注释是可以看到特征点的匹配情况
def ORB(img1,img2):
orb= cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
# img_out = cv2.drawKeypoints(img2, kp2, img2, flags=2)
# plt.imshow(img_out), plt.title('Test3'),
# plt.axis('off')
# plt.show()
# plt.imshow(img_out)
# matches = bf.knnMatch(des1, des2, k=1)
# 获得匹配结果
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作为下限。
'''
matches = sorted(matches, key=lambda matches: matches.distance)
# 准备空的掩膜 画好的匹配项
good = []
good_match = []
for x in matches:
if x.distance <= max(2 * min_distance, 20):
good.append(x)
if len(good) > 10:
# Construct the two sets of points
if isinstance(kp1[0], cv2.KeyPoint):
src_points = np.float32([kp1[good[idx].queryIdx].pt for idx in range(len(good))])
dst_points = np.float32([kp2[good[idx].trainIdx].pt for idx in range(len(good))])
else:
src_points = np.float32([kp1[good[idx].queryIdx] for idx in good])
dst_points = np.float32([kp2[good[idx].trainIdx] for idx in good])
# # Compute the homography between the two sets of points and compute the ratio of matched points
H, status = cv2.findHomography(src_points, dst_points, cv2.RANSAC, int(len(good) / 2))
# #matchesMask = status.ravel().tolist()
# src_points = np.array(src_points).reshape(-1,1,2)
# else:
# print("Not enough matches are found ",len(matches), 10))
# matchesMask = None
# draw_params = dict(matchColor=(0, 0, 255), # draw matches in green color
# singlePointColor=None,
# matchesMask=matchesMask, # draw only inliers
# flags=2)
# img3 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params)
# plt.imshow(img3), plt.title('Test3'),
# plt.axis('off')
# plt.show()
src_points = np.array(src_points).reshape(-1,1,2)
return src_points,H
如果运行上面代码放两张图片可以看到这样的效果:
注:你会遇到sift错误,那是因为opencv对sift有版权限制,你可以pip install opencv 4.4版本。