Determine if an image exists within a larger image, and if so, find it, using Python
我需要一个正在处理的Python程序,以便能够拍摄小图像,确定它是否存在于大图像中,如果存在,请报告其位置。如果没有,请报告。 (在我的情况下,大图像将是屏幕截图,小图像将是在HTML5画布中的屏幕上可能出现或可能不在屏幕上的图像。)在线查看时,我发现有关OpenCV中模板匹配的信息,具有出色的Python绑定。我根据在网上找到的非常相似的代码尝试了以下操作,同时也使用了numpy:
1 2 3 4 5 6 | import cv2 import numpy as np image = cv2.imread("screenshot.png") template = cv2.imread("button.png") result = cv2.matchTemplate(image,template,cv2.TM_CCOEFF_NORMED) StartButtonLocation = np.unravel_index(result.argmax(),result.shape) |
这没有做我需要做的,因为它总是在较大的图像中返回一个点;无论匹配多么糟糕,匹配最接近的点。我想要一种能够在大图像中找到与小图像精确匹配的像素,并且如果不存在,则会引发异常,或者返回
如果您正在寻找
该想法是在较大的
1 2 3 | im = np.atleast_3d(im) H, W, D = im.shape[:3] h, w = tpl.shape[:2] |
通过使用智能积分图像,可以真正快速地计算从每个像素开始的
1 | sat = im.cumsum(1).cumsum(0) |
,它具有非常好的属性,例如仅用4次算术运算就可以计算一个窗口中所有值的总和:
因此,通过计算模板的总和并将其与整数图像上的
1 2 | iA, iB, iC, iD = sat[:-h, :-w], sat[:-h, w:], sat[h:, :-w], sat[h:, w:] lookup = iD - iB - iC + iA |
上面是图像中所有可能的
这将减少可能的窗口数量(在我的一项测试中减少到2个)。最后一步是检查与模板的完全匹配:
1 2 3 4 | posible_match = np.where(np.logical_and.reduce([lookup[..., i] == tplsum[i] for i in range(D)])) for y, x in zip(*posible_match): if np.all(im[y+1:y+h+1, x+1:x+w+1] == tpl): return (y+1, x+1) |
请注意,此处的
放在一起:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def find_image(im, tpl): im = np.atleast_3d(im) tpl = np.atleast_3d(tpl) H, W, D = im.shape[:3] h, w = tpl.shape[:2] # Integral image and template sum per channel sat = im.cumsum(1).cumsum(0) tplsum = np.array([tpl[:, :, i].sum() for i in range(D)]) # Calculate lookup table for all the possible windows iA, iB, iC, iD = sat[:-h, :-w], sat[:-h, w:], sat[h:, :-w], sat[h:, w:] lookup = iD - iB - iC + iA # Possible matches possible_match = np.where(np.logical_and.reduce([lookup[..., i] == tplsum[i] for i in range(D)])) # Find exact match for y, x in zip(*possible_match): if np.all(im[y+1:y+h+1, x+1:x+w+1] == tpl): return (y+1, x+1) raise Exception("Image not found") |
它适用于灰度图像和彩色图像,并在
一个实际例子:
1 2 3 4 5 6 7 | >>> from skimage import data >>> im = gray2rgb(data.coins()) >>> tpl = im[170:220, 75:130].copy() >>> y, x = find_image(im, tpl) >>> y, x (170, 75) |
并说明结果:
将原始图像保留在模板右边。这是完全匹配的内容:
1 2 3 4 | >>> fig, ax = plt.subplots() >>> imshow(im) >>> rect = Rectangle((x, y), tpl.shape[1], tpl.shape[0], edgecolor='r', facecolor='none') >>> ax.add_patch(rect) |
最后,只是测试的
图像中两个窗口的总和是相同的,但该函数的最后一步将筛选出与模板不完全匹配的那个。
由于您对OpenCV感到满意,所以我建议您从已经做的事情开始,并获得最佳匹配。找到最匹配的位置后,您可以检查它实际上是否是一个很好的匹配。
检查匹配是否良好就像提取匹配图像并将其与模板进行比较一样容易。要提取图像,您可能需要使用
提取图像后,您应该可以使用