如何根据与其他匹配项的接近程度来过滤外围匹配项?

How can I filter outlying matches based on proximity to other matches?

如何根据与其他匹配项的接近程度来过滤异常匹配项?

我正在尝试在大图像中找到相似的小图像。模板匹配似乎不能很好地处理微小差异,所以我正在尝试特征匹配方法。经过大量修改后,我可以让它在匹配方面做得相当不错,但异常值会导致问题。我的代码中有单应性,这似乎没有必要,但它对获得正确的匹配有积极影响。还有其他更有效的替代方法吗?

最终,我想找到匹配项,(见图1)过滤掉与较小图像不对齐的关键点,(见图2)确定大图像中较小图像的边界, 然后找到该边界中心的坐标。

https://ibb.co/c0xC6m

https://ibb.co/mjSZK6

其他图片:

要搜索的图片:(它们未格式化为图片,因为错误提示我有未格式化的代码。)

https://i.stack.imgur.com/VyVAv.png

未经编辑的世界地图:

https://i.stack.imgur.com/5u3FN.png

原始搜索结果:

https://i.stack.imgur.com/VrX63.png

import cv2
import numpy as np
from matplotlib import pyplot as plt
import remove_map_dots as rm

MIN_MATCH_COUNT = 0

img1 = rm.removemapdots()
img2 = cv2.imread('worldmapsnippet1.png')

surf = cv2.xfeatures2d.SURF_create(hessianThreshold=10, upright=True, extended=True)

# find the keypoints and descriptors with SURF/SIFT
kp1, des1 = surf.detectAndCompute(img1, None)
kp2, des2 = surf.detectAndCompute(img2, None)

FLANN_INDEX_KDTREE = 0
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:
    good.append(m)

if len(good)>MIN_MATCH_COUNT:
    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, 10) #RANSAC LMEDS RHO
    matchesMask = mask.ravel().tolist()

    h, w, _ = img1.shape
    pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)
    dst = cv2.perspectiveTransform(pts, M)

    img2 = cv2.polylines(img2, [np.int32(dst)], True, 255, 3, cv2.LINE_AA)
    print(h)
    print(w)
else:
    print("Not enough matches are found - %d/%d" % (len(good), MIN_MATCH_COUNT))
    matchesMask = None

draw_params = dict(matchColor = (0, 255, 0), # 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.show()

正如评论中所讨论的,您的模板匹配方法的问题确实是模板和图像的大小。模板大于模板的相应区域,给出错误的读数。简单的解决方案是调整模板大小,使区域与地图中正确大小的区域完全对应。

特征匹配也可以用于此目的,但模板匹配在这里更有意义。两个图像之间的唯一区别是翻译,模板匹配可以很好地处理。

通过模板匹配,还可以轻松进行出色的优化,例如将搜索区域缩小到地图中最后找到的位置周围。您还可以通过查看最后几个找到的位置来创建一个阈值——这样您就知道什么时候您没有找到正确的位置并且需要重新查看整个地图。例如,如果你传送它不会在最后一个位置周围,所以你需要遍历整个图像。但是你知道最后(比如)5 帧的 SSD 图像的 min 是 [100, 150, 130, 180, 100] 所以如果你的下一帧有很大不同(比如 min在您所在的地区是 500)然后您再次检查整个地图并找到最小值,然后再次开始跟踪该地区。