简体   繁体   English

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

[英]How to find a template in an image using a mask (or transparency) with OpenCV and Python?

Let us assume we are looking for this template:让我们假设我们正在寻找这个模板:

停止

The corners of our template are transparent, so the background will vary, like so:我们模板的角是透明的,所以背景会有所不同,如下所示:

停在月亮上

停在珠穆朗玛峰

停在树叶上

Assuming we could use the following mask with our template:假设我们可以在我们的模板中使用以下掩码:

停止 停止面具

It would be very easy to find it.找到它会很容易。

What I have tried:我尝试过的:

I have tried matchTemplate but it doesn't support masks (as far as I know), and using the alpha channel (transparency) in the template does not achieve this, as it compares the alpha channels instead of ignoring those pixels.我尝试过matchTemplate但它不支持蒙版(据我所知),并且在模板中使用 alpha 通道(透明度)并不能实现这一点,因为它比较了 alpha 通道而不是忽略这些像素。

I have also looked into "region of interest", which I thought would be the solution, but with it you can only specify a rectangular area.我还研究了“感兴趣区域”,我认为这将是解决方案,但使用它您只能指定一个矩形区域。 I'm not even sure if it works on the template or not.我什至不确定它是否适用于模板。

I'm sure this is possible to do by writing my own algorithm, but I was hoping this is possible via.我确信通过编写我自己的算法可以做到这一点,但我希望这可以通过。 standard OpenCV to avoid reinventing the wheel.标准 OpenCV 以避免重新发明轮子。 Not to mention, it would most likely be more optimised than my own.更不用说,它很可能比我自己的更优化。

So, how could I do something like this with OpenCV + Python?那么,我怎么能用 OpenCV + Python 做这样的事情呢?

This could be achieved using only matchTemplate function, but a little workaround is needed.这可以仅使用matchTemplate函数来实现,但需要一些解决方法。

Lets analyse the default metrics( CV_TM_SQDIFF_NORMED ).让我们分析默认指标( CV_TM_SQDIFF_NORMED )。 According to matchTemplate documentation the default metrics looks like this根据matchTemplate 文档,默认指标如下所示

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

Where I is image matrix, T is template, R is result matrix.其中I是图像矩阵, T是模板, R是结果矩阵。 Summation is done over template coordinates x' and y' ,对模板坐标x'y'进行求和,

So, lets alter this metrics by inserting weight matrix W , which has the same dimensions as T .因此,让我们通过插入与T具有相同维度的权重矩阵W更改此指标。

Q(x, y) = sum W(x', y')*(I(x+x', y+y') - T(x', y'))^2

In this case, by setting W(x', y') = 0 you can actually make pixel be ignored.在这种情况下,通过设置W(x', y') = 0您实际上可以忽略像素。 So, how to make such metrics?那么,如何制定这样的指标呢? With simple math:用简单的数学:

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)}

So, we divided Q metrics into tree separate sums.因此,我们将Q度量划分为树单独的总和。 And all those sums could be calculated with matchTemplate function (using CV_TM_CCORR method).所有这些总和都可以使用matchTemplate函数(使用CV_TM_CCORR方法)计算。 Namely

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)

The last element is a constant, so, for minimisation it does not have any effect.最后一个元素是一个常数,因此,对于最小化它没有任何影响。 On the other hand, it still might me useful to see if our template have perfect match (if Q is approaching to zero).另一方面,查看我们的模板是否完美匹配(如果 Q 接近零)仍然可能有用。 Nonetheless, for last element we actually do not need matchTemplate function, since it could be calculated directly.尽管如此,对于最后一个元素,我们实际上不需要matchTemplate函数,因为它可以直接计算。

The final pseudocode looks like this:最终的伪代码如下所示:

result = matchTemplate(I^2, W, method=2) - matchTemplate(I, 2*W*T, method=2) + as.scalar(sum(W*T^2))

Does it really do exactly as defined?它真的完全按照定义做吗? Mathematically yes.数学上是的。 Practically, there is some small rounding error, because matchTemplate function works on 32-bit floating-point, but I believe it is not a big problem.实际上,存在一些小的舍入误差,因为matchTemplate函数适用于 32 位浮点数,但我相信这不是一个大问题。

Please note, that you can extent analysis and have weighted equivalents for any metrics offered by matchTemplate .请注意,您可以matchTemplate分析并为matchTemplate提供的任何指标加权等效matchTemplate

This actually worked for me.这实际上对我有用。 I am sorry I don't give actual code.很抱歉我没有提供实际代码。 I am working in R, so I don't have the code in Python.我在 R 中工作,所以我没有 Python 中的代码。 But idea is quite straightforward.但想法很简单。

I hope this will help.我希望这将有所帮助。

What worked for me the one time I needed this was to fill the "mask" areas with white noise.有一次我需要它时对我有用的是用白噪声填充“遮罩”区域。 Then it gets effectively washed out of the correlation when looking for matches.然后,在寻找匹配项时,它会有效地从相关性中消失。 Otherwise I got, as I presume you did, false matches on the masked areas.否则,正如我假设您所做的那样,我得到了蒙版区域的错误匹配。

One answer to your question is convolution .您的问题的一个答案是卷积 Use the template as kernel and filter the image.使用模板作为内核并过滤图像。

The destination Mat will have dense bright areas where your template might be.目标 Mat 将有密集的明亮区域,您的模板可能位于该区域。 You'll have to cluster the results (eg Mean-shift).您必须对结果进行聚类(例如均值漂移)。

In that way, you'll have a very simplistic implementation of the Generalized Hough Transform or a Template-based convolution matching .这样,您将获得一个非常简单的广义霍夫变换或基于模板的卷积匹配

ImageMagick has logic for finding subimages in other images and it works quite well. ImageMagick 具有在其他图像中查找子图像的逻辑,并且效果很好。

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

I've used it to find and blur watermarks off some products.我用它来查找和模糊某些产品的水印。 Don't ask.不要问。

(Sometimes you have to do what you have to do..) (有时你必须做你必须做的..)

Imagemagick 7.0.3.9 now has a masked compare capability so that you can limit the template matching region. Imagemagick 7.0.3.9 现在具有屏蔽比较功能,以便您可以限制模板匹配区域。 See http://www.imagemagick.org/discourse-server/viewtopic.php?f=4&t=31053http://www.imagemagick.org/discourse-server/viewtopic.php?f=4&t=31053

Also, I see that OpenCV 3.0 now has masked template matching.另外,我看到 OpenCV 3.0 现在有屏蔽模板匹配。 See http://docs.opencv.org/3.0.0/df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329behttp://docs.opencv.org/3.0.0/df/dfb/group__imgproc__object.html#ga586ebfb0a7fb604b35a23d85391329be

However, it is only for method == CV_TM_SQDIFF and method == CV_TM_CCORR_NORMED.但是,它仅适用于方法 == CV_TM_SQDIFF 和方法 == CV_TM_CCORR_NORMED。 see python opencv matchTemplate is mask feature implemented?请参阅python opencv matchTemplate 是否实现了掩码功能?

2021 Update: I've been trying to find a solution for transparency in templates throughout the day, and I think I finally found a way to do it. 2021 年更新:我一整天都在努力寻找模板透明度的解决方案,我想我终于找到了一种方法。 matchTemplate() has a mask parameter, which apparently works exactly like OP wants it to: ignore certain pixels from a template when searching for it in another image. matchTemplate()有一个mask参数,它的工作方式显然与 OP 想要的完全一样:在另一个图像中搜索模板时忽略模板中的某些像素。 And since my templates already contain transparency in them, I decided to use my template as both a template and mask parameter.由于我的模板已经包含透明度,我决定将我的模板用作templatemask参数。 Surprisingly, it worked.令人惊讶的是,它奏效了。

I'm using JavaScript with opencv4nodejs, so the following python code snippet might be completely off, but the theory is there and I'm fairly positive it should work.我正在将 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)

Here's a gist for JavaScript with opencv4nodejs if you're interested. 如果您有兴趣,这里有一个关于带有 opencv4nodejs 的 JavaScript 的要点。

Now that I think about it, it seems really stupid and way too good to be true, but I've been getting good matches ( 0.98+ ) on most tests.现在我想想,这似乎真的很愚蠢,而且好得0.98+ ,但我在大多数测试中都得到了很好的匹配 ( 0.98+ )。 Hope this helps!希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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