繁体   English   中英

如何使用 OpenCV 和 Python 的蒙版(或透明度)在图像中查找模板?

[英]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 中的代码。 但想法很简单。

我希望这将有所帮助。

有一次我需要它时对我有用的是用白噪声填充“遮罩”区域。 然后,在寻找匹配项时,它会有效地从相关性中消失。 否则,正如我假设您所做的那样,我得到了蒙版区域的错误匹配。

您的问题的一个答案是卷积 使用模板作为内核并过滤图像。

目标 Mat 将有密集的明亮区域,您的模板可能位于该区域。 您必须对结果进行聚类(例如均值漂移)。

这样,您将获得一个非常简单的广义霍夫变换或基于模板的卷积匹配

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 想要的完全一样:在另一个图像中搜索模板时忽略模板中的某些像素。 由于我的模板已经包含透明度,我决定将我的模板用作templatemask参数。 令人惊讶的是,它奏效了。

我正在将 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM