如何在一张图片中找到包含的另一张图片?

70

我目前正在构建一个类似搜索引擎和画廊的网络漫画平台,专注于引用来源并为作者提供信用。

我正在尝试找到一种方法来搜索图像以查找其中的人物。

例如:

cyanide and happiness

假设我将红色角色和绿色角色保存为红衣人和绿衣人,那么如何确定图片是否包含其中之一。

这不需要完全识别或其他什么,因为这只是我想要创建的一种附加功能,但我不知道从哪里开始。我已经尝试了很多关于图像识别的谷歌搜索,但没有找到太有用的内容。

值得一提的是,我希望使用Python完成此项任务。


3
请看 sikuli脚本 - JBernardo
我不认为Sikuli适用于这种情况。Sikuli似乎只适用于GUI界面。这些是用户上传到Web服务器上的图片。 - Adam
Sikuli 不仅适用于 GUI。你技术上可以使用它来运行任何你想要的 Jython 脚本。你可以编写一个脚本,打开用户图像,然后查找你想要找到的图像模式。这只是一个初步的想法。 - Snaxib
然而,Sikuli不支持图像的缩放或旋转... - Adam
4个回答

87

Moshe's answer只涵盖了在给定图片中仅包含一次的匹配模板。这里是如何同时匹配多个模板:

import cv2
import numpy as np

img_rgb = cv2.imread('mario.png')
template = cv2.imread('mario_coin.png')
w, h = template.shape[:-1]

res = cv2.matchTemplate(img_rgb, template, cv2.TM_CCOEFF_NORMED)
threshold = .8
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):  # Switch columns and rows
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)

cv2.imwrite('result.png', img_rgb)

(注:我更改和修复了原始代码中的一些“错误”)

结果:

detect mario coins (before/after)

来源: https://opencv24-python-tutorials.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html#template-matching-with-multiple-objects

(翻译:)

14
我用你的代码测试了另一件事,经过我测试,似乎应该将“w,h = template.shape[:-1]”改为“h,w = template.shape[:-1]”,至少对于我的测试图像是这样的(在三组图像中均如此)。 - JimR
1
只需从他的答案中的源链接获取源代码;它是最新的并且可用。 - James T.
1
这是最好的。 - Polamin Singhasuwich

79

对于未来可能遇到这个问题的任何人。

这可以通过模板匹配完成。简而言之,模板匹配是寻找一个图像在另一个图像中的精确匹配。

以下是如何在Python中实现它的示例:

import cv2

method = cv2.TM_SQDIFF_NORMED

# Read the images from the file
small_image = cv2.imread('small_image.png')
large_image = cv2.imread('large_image.jpeg')

result = cv2.matchTemplate(small_image, large_image, method)

# We want the minimum squared difference
mn,_,mnLoc,_ = cv2.minMaxLoc(result)

# Draw the rectangle:
# Extract the coordinates of our best match
MPx,MPy = mnLoc

# Step 2: Get the size of the template. This is the same size as the match.
trows,tcols = small_image.shape[:2]

# Step 3: Draw the rectangle on large_image
cv2.rectangle(large_image, (MPx,MPy),(MPx+tcols,MPy+trows),(0,0,255),2)

# Display the original image with the rectangle around the match.
cv2.imshow('output',large_image)

# The image is only displayed if we call this
cv2.waitKey(0)

2
我同意Moshe的看法,但我认为应该是cv2.matchtemplate(large_image, small_image, method)。此外,这里还有另一个良好的关于Python中模板匹配信息的资源。 - devonbleibtrey
1
很奇怪,from cv2 import cv 会引发 ImportError: cannot import name 'cv' 错误,而 import cv2 却可以正常工作... - jeromej
1
解决方案:好的,因为我在使用Py3,实际上它使用的是OpenCV3,尽管它仍然被导入为“cv2”,所以一些东西已经改变了位置/名称。 - jeromej
如果其中一个图像在另一个图像中作为低透明度存在(其中一个输入图像被水印在另一个图像中),这样做还能起作用吗? - master_dodo
我必须在Ubuntu 20.04上执行sudo apt-get install python3-opencv才能使其正常工作。 - brewmanz

2

重要提示:matchTemplate甚至能够检测调整大小和旋转的模板。以下是代码和输出。

import matplotlib.pyplot as plt
import numpy as np
import cv2

image = cv2.imread('/content/picture.png')
template = cv2.imread('/content/penguin.png')
heat_map = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)

h, w, _ = template.shape
y, x = np.unravel_index(np.argmax(heat_map), heat_map.shape)
cv2.rectangle(image, (x,y), (x+w, y+h), (0,0,255), 5)

plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))

图片: 图片 模板: 企鹅 结果: 检测到

详细解释在这里(我的博客):simple-ai.net/find-and-replace-in-image


1
博客链接已失效。 - Ezequiel Adrian
2
对于这个简化的例子,使用调整大小和旋转可能有效,但在稍微复杂一些的情况下就不行了。声称这是误导性的。 - rob

1

OpenCV有一个Python接口,您可以查看。如果字符不会改变太多,您可以尝试使用matchTemplate函数。

这里是官方的教程(该教程使用C++接口编写,但您应该能够从中获得如何在Python中使用该函数的好主意)。


2
没有一个链接可用。-.- - Urban P.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接