29

假设我们正在寻找这个模板:

停止

我们模板的角是透明的,所以背景会有所不同,如下所示:

停在月亮上

停在珠穆朗玛峰上

停在树叶上

假设我们可以在模板中使用以下掩码:

停止 停止面具

很容易找到它。

我试过的:

我已经尝试过matchTemplate,但它不支持蒙版(据我所知),并且在模板中使用 alpha 通道(透明度)并不能实现这一点,因为它比较 alpha 通道而不是忽略这些像素。

我还研究了“感兴趣的区域”,我认为这将是解决方案,但使用它您只能指定一个矩形区域。我什至不确定它是否适用于模板。

我确信这可以通过编写我自己的算法来实现,但我希望这可以通过。标准的 OpenCV 以避免重新发明轮子。更不用说,它很可能比我自己的更优化。

那么,我怎么能用 OpenCV + Python 做这样的事情呢?

4

6 回答 6

9

这可以仅使用matchTemplate函数来实现,但需要一些解决方法。

让我们分析默认指标(CV_TM_SQDIFF_NORMED)。根据matchTemplate 文档 ,默认指标如下所示

R(x, y) = sum (I(x+x', y+y') - T(x', y'))^2

哪里I是图像矩阵,T是模板,R是结果矩阵。求和是在模板坐标上完成x'y'

W因此,让我们通过插入与 具有相同维度的 权重矩阵来更改此指标T

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.

这实际上对我有用。对不起,我没有给出实际的代码。我在 R 中工作,所以我没有 Python 中的代码。但想法很简单。

我希望这将有所帮助。

于 2014-07-15T03:34:26.347 回答
3

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

于 2013-03-21T01:41:20.383 回答
2

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

目标 Mat 将在您的模板所在的位置具有密集的明亮区域。您必须对结果进行聚类(例如均值偏移)。

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

于 2013-03-19T14:45:54.067 回答
2

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 是否实现了掩码功能?

于 2016-12-29T21:42:24.620 回答
1

ImageMagick 具有在其他图像中查找子图像的逻辑,并且效果很好。

compare -verbose -dissimilarity-threshold 0.1 -subimage-search subimage bigimage

我用它来查找和模糊某些产品的水印。不要问。

(有时你必须做你必须做的事情..)

于 2013-03-19T15:45:24.983 回答
1

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+在大多数测试中都得到了很好的匹配 ( )。希望这可以帮助!

于 2021-03-30T19:54:13.227 回答