使用 Python 在 OpenCV 中删除或防止重复模板匹配

Mar*_*ams 5 python opencv

我有一张地图,上面有许多类似的符号(树)分布在地图上。我正在使用 opencv 来查找所有符号的 X、Y 坐标。

它运行良好,但我收到了大量重复结果。如果我增加过滤器阈值,重复的数量就会减少,因为很多符号都被遗漏了。我尝试编写一些代码来根据接近度过滤结果,但我运气不佳。有没有人知道我可以在这里尝试什么?

img_rgb = cv2.imread('images/map.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('images/tree.jpg',0)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)

threshold = 0.35
matches = np.where( res >= threshold)

tree_count = 0
for pt in matches:
    tree_count += 1
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (255,0,0), 1)

cv2.imwrite('found_map.jpg',img_rgb)
print "Done " + map
Run Code Online (Sandbox Code Playgroud)

Joã*_*cho 11

您可以跟踪已检测到树的图像区域(使用遮罩)。然后,例如,如果尚未标记每个匹配项的中心,则仅增加树计数器。

代码:

img_rgb = cv2.imread('trees.png')
template = cv2.imread('apple_tree.png')
h, w = template.shape[:2]

res = cv2.matchTemplate(img_rgb, template, cv2.TM_CCOEFF_NORMED)

threshold = 0.95
loc = np.where( res >= threshold)

tree_count = 0
mask = np.zeros(img_rgb.shape[:2], np.uint8)
for pt in zip(*loc[::-1]):
    if mask[pt[1] + int(round(h/2)), pt[0] + int(round(w/2))] != 255:
        mask[pt[1]:pt[1]+h, pt[0]:pt[0]+w] = 255
        tree_count += 1
        cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,255,0), 1)

cv2.imwrite('found_map.jpg',img_rgb)
print("Found {} trees in total!".format(tree_count))
Run Code Online (Sandbox Code Playgroud)

之前(不删除重复项): 在此处输入图片说明

在此处输入图片说明

之后 (使用掩码删除重复项): 在此处输入图片说明 在此处输入图片说明

您可以在底部图像中注意到较细的绿线,说明我们检测到 3 棵苹果树,而不是 13 棵!


M4r*_*ini 0

我可以想到两个选择。

  1. 对结果图像进行形态侵蚀,直到只剩下点。很多模块都有这个功能。例如 opencv 和 skimage。

  2. 使用结果图像,您可以尝试计算轮廓并提取每个轮廓的内部。

如果没有一些样本数据,很难说什么是最好的选择。不同的数据通常需要不同的方法。