Python OpenCV SIFT 特征匹配查找多个相同元素
def 图片查找_特征匹配_全部(big_img, small_img, threshold=0.7, min_match_count=4, maxcnt=0):
'''
使用sift算法进行多个相同元素的查找
Args:
big_img (numpy.ndarray): 大图
small_img (numpy.ndarray): 需要查找的图片
threshold (float): 阈值,当相识度小于该阈值的时候,就忽略掉
min_match_count (int): 最小匹配数量
maxcnt (int): 限制匹配的数量
Returns:
list: 包含匹配结果的列表,每个元素为字典,包含中心点坐标、矩形框以及置信度
例如:
[{'result': (100, 200), 'rectangle': [(10, 10), (10, 210), (210, 210), (210, 10)], 'confidence': 0.8}]
'''
sift = cv2.SIFT_create(nfeatures=0, nOctaveLayers=10)
flann = cv2.FlannBasedMatcher({'algorithm': 1, 'trees': 5}, dict(checks=50))
g1 = cv2.cvtColor(small_img, cv2.COLOR_BGR2GRAY)
g2 = cv2.cvtColor(big_img, cv2.COLOR_BGR2GRAY)
kp_sch, des_sch = sift.detectAndCompute(g1, None)
if len(kp_sch) < min_match_count:
return None
kp_src, des_src = sift.detectAndCompute(g2, None)
if len(kp_src) < min_match_count:
return None
result = []
while True:
# 匹配两个图片中的特征点,k=2表示每个特征点取2个最匹配的点
matches = flann.knnMatch(des_sch, des_src, k=2)
good = []
for m, n in matches:
# 剔除掉跟第二匹配太接近的特征点
if m.distance < threshold * n.distance:
good.append(m)
if len(good) < min_match_count:
break
sch_pts = np.float32([kp_sch[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
img_pts = np.float32([kp_src[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
# M是转化矩阵
M, mask = cv2.findHomography(sch_pts, img_pts, cv2.RANSAC, 5.0)
matches_mask = mask.ravel().tolist()
# 计算四个角矩阵变换后的坐标,也就是在大图中的坐标
h, w = small_img.shape[:2]
pts = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)
dst = cv2.perspectiveTransform(pts, M)
# trans numpy arrary to python list
# [(a, b), (a1, b1), ...]
pypts = []
for npt in dst.astype(int).tolist():
pypts.append(tuple(npt[0]))
lt, br = pypts[0], pypts[2]
middle_point = (lt[0] + br[0]) / 2, (lt[1] + br[1]) / 2 # 计算中心点
result.append(dict(
result=middle_point,
rectangle=pypts,
confidence=min(1.0 * matches_mask.count(1) / 10, 1.0) # min(1.0 * matches_mask.count(1) / 10, 1.0)
))
if maxcnt and len(result) >= maxcnt:
break
# 从特征点中删掉那些已经匹配过的, 用于寻找多个目标
qindexes, tindexes = [], []
for m in good:
# 将已经找到的先存起来 后面方便删除
qindexes.append(m.queryIdx) # need to remove from kp_sch
tindexes.append(m.trainIdx) # need to remove from kp_img
def filter_index(tt, arr):
r = np.ndarray(0, np.float32)
for i, item in enumerate(arr):
if tt == 1:
if i not in qindexes:
r = np.append(r, item)
else:
if i not in tindexes:
r = np.append(r, item)
return r
# 更新数组
kp_src = filter_index(1, kp_src)
des_src = filter_index(0, des_src)
return result
if __name__ == '__main__':
big_img = cv2.imdecode(np.fromfile(file=r'C:\Users\Administrator\Desktop\result_11.jpg', dtype=np.uint8), cv2.IMREAD_COLOR) # 加载大图
small_img = cv2.imdecode(np.fromfile(file=r'C:\Users\Administrator\Desktop\zhuye1.bmp', dtype=np.uint8), cv2.IMREAD_COLOR)
ret = 图片查找_特征匹配_全部(big_img, small_img)
print(ret)
关于“cv2.error: OpenCV(4.5.2) c:\users\runneradmin\appdata\local\temp\pip-req-build-vi271kac\opencv\modules\flann\include\opencv2\flann\nn_index.h:71: error: (-215:Assertion failed) queries.cols == veclen() in function 'cvflann::NNIndex<struct cvflann::L2
该错误表示 des_sch 和 des_src 的维度不匹配。可能的原因是:
- 图像大小不一致:
small_img和big_img的大小可能不一致,导致特征描述符的维度不同。请确保两张图片的大小一致。 - SIFT 参数:
sift.detectAndCompute()的参数可能导致特征描述符的维度不同。请检查参数,确保参数设置一致。 - 特征点数量: 如果其中一张图片的特征点数量过少,会导致维度不匹配。可以调整
sift.detectAndCompute()的nfeatures参数,或增加min_match_count的值。
建议
- 调试: 使用
print(des_sch.shape, des_src.shape)打印des_sch和des_src的维度,检查是否一致。 - 更换算法: 尝试使用其他的特征匹配算法,比如基于 ORB 特征的匹配算法,来替代 FLANN 进行特征匹配。
- 更新 OpenCV: 尝试更新 OpenCV 库,可能可以解决问题。
如果以上方法都无法解决问题,请提供更多错误信息和代码片段,以便更准确地定位问题。
注意: 代码中使用了 cv2.imdecode(np.fromfile(...), cv2.IMREAD_COLOR) 加载图片,这是一种比较高效的读取图片的方式,建议使用。
原文地址: https://www.cveoy.top/t/topic/hLNz 著作权归作者所有。请勿转载和采集!