[英]How to find a template in an image using a mask (or transparency) with OpenCV and Python?
让我们假设我们正在寻找这个模板:
我们模板的角是透明的,所以背景会有所不同,如下所示:
假设我们可以在我们的模板中使用以下掩码:
找到它会很容易。
我尝试过的:
我尝试过matchTemplate
但它不支持蒙版(据我所知),并且在模板中使用 alpha 通道(透明度)并不能实现这一点,因为它比较了 alpha 通道而不是忽略这些像素。
我还研究了“感兴趣区域”,我认为这将是解决方案,但使用它您只能指定一个矩形区域。 我什至不确定它是否适用于模板。
我确信通过编写我自己的算法可以做到这一点,但我希望这可以通过。 标准 OpenCV 以避免重新发明轮子。 更不用说,它很可能比我自己的更优化。
那么,我怎么能用 OpenCV + Python 做这样的事情呢?
这可以仅使用matchTemplate
函数来实现,但需要一些解决方法。
让我们分析默认指标( CV_TM_SQDIFF_NORMED
)。 根据matchTemplate 文档,默认指标如下所示
R(x, y) = sum (I(x+x', y+y') - T(x', y'))^2
其中I
是图像矩阵, T
是模板, R
是结果矩阵。 对模板坐标x'
和y'
进行求和,
因此,让我们通过插入与T
具有相同维度的权重矩阵W
更改此指标。
Q(x, y) = sum W(x', y')*(I(x+x', y+y') - T(x', y'))^2
在这种情况下,通过设置W(x', y') = 0
您实际上可以忽略像素。 那么,如何制定这样的指标呢? 用简单的数学:
Q(x, y) = sum W(x', y')*(I(x+x', y+y') - T(x', y'))^2
= sum W(x', y')*(I(x+x', y+y')^2 - 2*I(x+x', y+y')*T(x', y') + T(x', y')^2)
= sum {W(x', y')*I(x+x', y+y')^2} - sum{W(x', y')*2*I(x+x', y+y')*T(x', y')} + sum{W(x', y')*T(x', y')^2)}
因此,我们将Q
度量划分为树单独的总和。 所有这些总和都可以使用matchTemplate
函数(使用CV_TM_CCORR
方法)计算。 即
sum {W(x', y')*I(x+x', y+y')^2} = matchTemplate(I^2, W, method=2)
sum{W(x', y')*2*I(x+x', y+y')*T(x', y')} = matchTemplate(I, 2*W*T, method=2)
sum{W(x', y')*T(x', y')^2)} = matchTemplate(T^2, W, method=2) = sum(W*T^2)
最后一个元素是一个常数,因此,对于最小化它没有任何影响。 另一方面,查看我们的模板是否完美匹配(如果 Q 接近零)仍然可能有用。 尽管如此,对于最后一个元素,我们实际上不需要matchTemplate
函数,因为它可以直接计算。
最终的伪代码如下所示:
result = matchTemplate(I^2, W, method=2) - matchTemplate(I, 2*W*T, method=2) + as.scalar(sum(W*T^2))
它真的完全按照定义做吗? 数学上是的。 实际上,存在一些小的舍入误差,因为matchTemplate
函数适用于 32 位浮点数,但我相信这不是一个大问题。
请注意,您可以matchTemplate
分析并为matchTemplate
提供的任何指标加权等效matchTemplate
。
这实际上对我有用。 很抱歉我没有提供实际代码。 我在 R 中工作,所以我没有 Python 中的代码。 但想法很简单。
我希望这将有所帮助。
有一次我需要它时对我有用的是用白噪声填充“遮罩”区域。 然后,在寻找匹配项时,它会有效地从相关性中消失。 否则,正如我假设您所做的那样,我得到了蒙版区域的错误匹配。
ImageMagick 具有在其他图像中查找子图像的逻辑,并且效果很好。
compare -verbose -dissimilarity-threshold 0.1 -subimage-search subimage bigimage
我用它来查找和模糊某些产品的水印。 不要问。
(有时你必须做你必须做的..)
Imagemagick 7.0.3.9 现在具有屏蔽比较功能,以便您可以限制模板匹配区域。 见http://www.imagemagick.org/discourse-server/viewtopic.php?f=4&t=31053
另外,我看到 OpenCV 3.0 现在有屏蔽模板匹配。 见http://docs.opencv.org/3.0.0/df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be
但是,它仅适用于方法 == CV_TM_SQDIFF 和方法 == CV_TM_CCORR_NORMED。 请参阅python opencv matchTemplate 是否实现了掩码功能?
2021 年更新:我一整天都在努力寻找模板透明度的解决方案,我想我终于找到了一种方法。 matchTemplate()
有一个mask
参数,它的工作方式显然与 OP 想要的完全一样:在另一个图像中搜索模板时忽略模板中的某些像素。 由于我的模板已经包含透明度,我决定将我的模板用作template
和mask
参数。 令人惊讶的是,它奏效了。
我正在将 JavaScript 与 opencv4nodejs 一起使用,因此以下 python 代码片段可能完全关闭,但理论已经存在,我相当肯定它应该可以工作。
# Import OpenCV
import cv2 as cv
# Read both the image and the template
image = cv.imread("image.png", cv.IMREAD_COLOR)
template = cv.imread("template.png", cv.IMREAD_COLOR)
# Match with template as both template and mask parameter
result = cv.matchTemplate(image, template, cv.TM_CCORR_NORMED, None, template)
如果您有兴趣,这里有一个关于带有 opencv4nodejs 的 JavaScript 的要点。
现在我想想,这似乎真的很愚蠢,而且好得0.98+
,但我在大多数测试中都得到了很好的匹配 ( 0.98+
)。 希望这可以帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.