如何在图像中使用掩膜(或透明度)找到模板,使用OpenCV和Python?
假设我们想找一个这样的模板:
这个模板的角落是透明的,所以背景会有所不同,比如:
假设我们可以用下面的遮罩来处理我们的模板:
这样就很容易找到它了。
我尝试过的:
我试过用 matchTemplate
,但我知道它不支持遮罩,而且在模板中使用透明通道并不能解决这个问题,因为它会比较透明通道,而不是忽略那些像素。
我还研究过“感兴趣区域”,我以为这会是解决方案,但用这个只能指定一个矩形区域。我甚至不确定它是否适用于模板。
我相信通过自己写算法是可以做到的,但我希望能通过标准的 OpenCV 来实现,这样就不用重新发明轮子了。更何况,标准的方法可能会比我自己的实现更优化。
那么,我该如何用 OpenCV 和 Python 来做这样的事情呢?
6 个回答
我之前遇到过类似的问题,解决的方法是把“遮罩”区域填充上白噪声。这样在寻找匹配的时候,这些区域就会被有效地“冲淡”,不会影响结果。否则,我想你也遇到过,我在遮罩区域得到了错误的匹配结果。
这个可以通过使用 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
提供的任何度量标准创建加权等价物。
这对我来说确实有效。抱歉我没有提供实际的代码。我是在 R 语言中工作,所以没有 Python 的代码。但这个想法非常简单明了。
希望这能帮到你。