OpenCV 模板匹配和透明度
Posted
技术标签:
【中文标题】OpenCV 模板匹配和透明度【英文标题】:OpenCV template matching and transparency 【发布时间】:2011-06-13 07:31:42 【问题描述】:OpenCV 在模板匹配过程中处理图像透明度的方式是什么?
问题是模板图像需要有透明部分,因为在原始图像中,这些地方可能有任何东西。
我尝试了所有方法,但都没有产生积极的结果(例如未正确检测到模板在原始图像中的位置)。
【问题讨论】:
在最大值上设置一个阈值。如果低于阈值,则图像不包含模板。您必须根据经验确定阈值的度量。 找不到图片。 =( @anatolytechtonik 抱歉,我没有它们了(已经 5 年了)。 【参考方案1】:OpenCV 将透明度视为图像的一部分而不是忽略它,这可能会导致意外结果。我处理它的方式是使用具有透明度的模板作为template
和matchTemplate()
中的mask
参数。我已经更详细地回答了类似的问题here,也许它会有所帮助。
【讨论】:
【参考方案2】:OpenCV 3.0 提供了对模板与掩码模板匹配的原生支持。参考new documentation:
参数:
图片...
模板 ...
结果...
方法...
mask 搜索模板的掩码。它必须与 templ 具有相同的数据类型和大小。默认不设置。
[稍微题外话]
请注意,模板与蒙面参考图像(较大的图像)匹配是不可能的。这是有道理的,因为 OpenCV 使用基于 FFT 的模板匹配。
因此,如果您只需要在参考图像的特定区域执行模板匹配,则需要为此实现自己的方法或屏蔽 cv::matchTemplate 的输出。
从头开始实现它应该可以弥补您只想在非常特定的区域(即:哈里斯角附近)搜索模板的情况。
【讨论】:
【参考方案3】:对于这个问题,我有一个稍微有点脑残的解决方案,它实际上似乎工作得相当好:用噪声替换模板图像的 alpha 通道,这或多或少地使透明区域在匹配过程中在统计上不显着。
例如,我的用例涉及在 ios 的屏幕截图中搜索表情符号字符。 iOS 键盘背景会根据上下文更改颜色,如果您在模板图像中提交特定的背景颜色,则匹配过程会出现问题。
这是 alpha 上的原始模板图像:
这是处理后的模板,alpha 通道填充了噪声:
我通过 OpenCV 文档中提供的Template Matching sample code 发送了处理后的模板图像。无论是深色还是浅色背景,都能以合理的可信度找到匹配项。
在深色背景上搜索:
在浅色背景上搜索:
相比之下,让模板的 Alpha 通道透明(或使用深色或浅色背景)不会返回可接受的匹配项。
【讨论】:
您的解决方案是一个运行不佳的解决方法。虽然通常 matchTemplate() 会返回 99% 甚至 100% 的匹配确定性(如果图像相同),但您的示例图像解决方案会返回匹配图像的 23% 的确定性。下一个不匹配的图像(其中一个表情符号)为 11%。这是匹配 (23%) 和非匹配 (11%) 图像之间的非常差的距离。笑脸与您的模板图像完全不同。因此,此解决方法很大程度上取决于您用来区分匹配和不匹配的阈值。您的解决方案给出了非常弱的结果 所以更好的解决方法如下:在第一步中使用您的方法(噪声模板)使用 matchTemplate() 查找匹配的可能位置,然后在第二步中将透明部分遮盖为黑色:模板和主图像在第一步中找到的位置以获得真正的确定性(最高 100%)。 如果你能去除表情符号周围的无用噪音,你会得到更好的确定性结果。您有高于和低于 16 个像素的噪点和每侧 5 个像素。去除它们后,确定性从 23% 增加到 57%。噪音越大识别越差! 非常智能的解决方案【参考方案4】:我遇到了同样的问题,我想到了一个解决方案。假设 referenceImageMask 和 templateMask 在好像素中有 1,在坏像素中有 0。并且那个 referenceImage 和 templateImage 已经被屏蔽并且坏像素中也有 0。
然后,模板匹配的第一个结果将给出图像之间未归一化的互相关。但是,一堆像素为零。
第二个模板匹配将为每个可能的偏移量提供两个图像中同时不同于零(未屏蔽)的像素数。
然后,通过该数字对相关性进行归一化应该会给出您(和我)想要的值。两幅图像中未被屏蔽的像素的平均乘积。
Image<Gray, float> imCorr = referenceImage.MatchTemplate(templateImage, Emgu.CV.CvEnum.TM_TYPE.CV_TM_CCORR);
Image<Gray, float> imCorrMask = referenceImageMask.MatchTemplate(templateMask, Emgu.CV.CvEnum.TM_TYPE.CV_TM_CCORR);
_imCorr = _imCorr.Mul(_imCorrMask.Pow(-1));
更新:实际上,此解决方案不起作用。因为opencv中互相关的实现使用了DFT,所以会有数值问题,不能用第二个互相关来修正第一个。
【讨论】:
【参考方案5】:如果您尝试将 Alpha 通道替换为黑色 RGB 颜色,SQDIFF/SQDIFF_N
选项将是一个解决方案。
至少这是我对同样问题的解决方案。从我的结果可以看出,这种方法对较亮的像素值很敏感,我抓住了这个机会。
【讨论】:
【参考方案6】:OpenCV 似乎不像您希望的那样处理 alpha。
你有两个选择:
-
编写您自己的将使用 Alpha 通道的互相关方法
转换您的图像,使您的 Alpha 通道变得无关紧要
由于第一个选项很简单,我将在这里探讨第二个选项。我将重新使用我之前提供给a similar question 的示例代码。如果您将互相关直接应用于图像,则背景会干扰模板匹配(特别是浅色背景部分)。如果您使用颜色通道,您会发现蓝色通道中的匹配给出了正确的结果。这取决于图像内容,并不是解决问题的一致方法。
另一种选择是对图像和模板进行边缘检测(例如Sobel),然后进行互相关。这是边缘检测图像(我在 GIMP 的 Luma 通道上使用了 Sobel 边缘检测器,然后进行了一些强度拉伸)。
如您所见,此处的 alpha 通道已变得无关紧要,因为大部分地形已变为零强度,并且不会对互相关计算做出贡献。所以现在可以直接应用互相关,得到想要的结果:
misha@misha-desktop:~/Desktop/***$ python cross-correlation.py map-blue.png building-maskz-blue.png
(163, 244)
最后,这是another related question。
附言。这是什么游戏?
【讨论】:
谢谢,但我在灰度图像和模板上使用 Sobel 并没有得到相同的结果(请参阅问题)。图片来自一个旧的 DOS 游戏 - Earth 2140。 您的图像不起作用的原因是因为没有边缘的区域不是黑色(它们是 127 中性灰色)。将它们与我的图像进行比较。您需要将非边缘区域设为零,这样它们才不会干扰互相关计算。 好的,我使用 cvConvertAbsScale 使非边缘区域为零。 (见问题)但是,我的 Sobel 仍然与您的不同(尤其是模板)。难道是我用 OpenCV 而你用 GIMP 做 Sobel 吗? 最有可能——正如我所提到的,我做了 Sobel,然后进行了一些强度缩放(因为这两个图像的缩放方式相同,这不会影响自相关,但让事情变得更容易看)。即使图像不完全相同,但只要边缘高且非边缘低,该方法就可以工作。您的 Sobel 图像看起来并非所有边缘(比较水平边缘)都被拾取。如果它让您感到困扰,请发布您的代码,我会在明天的某个时候使用它。 不,实际上索贝尔的技术很棒。当原始图像中有一个模板(甚至有点模糊,如所讨论的示例中)时,它总是会产生积极的结果。但是,我在图像中 多次出现 模板时遇到了问题(特别是当图像中没有模板时 - 请参阅问题示例)。【参考方案7】:我不确定,但透明度通道的处理方式与其他任何通道一样。如果模板中的像素是“透明的”,那么它在主图像上也应该是“透明的”。我只是在这里猜测。
【讨论】:
这就是问题所在。我需要模板匹配到模板图像中具有透明度的 ignore 像素。否则我将永远无法在原始图像中找到模板,因为在原始图像中,我正在寻找的对象周围可能有任何东西 去掉两者中的透明通道。那可以工作。或者您可以编写自己的模板匹配函数。 OpenCV 文档列出了用于各种方法的公式。您可以修改它们,使它们“尊重”像素的透明度。 Utkarash,你是对的:你只是在猜测。但现实世界比你想象的要复杂得多。当您编写自己的匹配函数时,使用给定的公式逐个像素地将图像与模板进行比较,即使在速度优化的 C++ 中,这将是不可接受的缓慢(运行长达一分钟)。 OpenCV 速度如此之快的原因是它在 matchTemplate() 中使用了 DFT(傅立叶变换)。但是代码非常复杂(并且没有任何 cmets),只有数学家才能理解。所以忘记编写自己的 matchTemplate() 函数吧!【参考方案8】:我认为您正在尝试在 OpenCV 中使用掩码进行模板匹配。我认为您可以尝试在模板上设置 ROI(感兴趣区域)。 This SO question shows how to do it。 (请注意,在该问题中,ROI 是在目标图像上设置的,而不是在模板上,但过程是相同的)。
【讨论】:
很有趣,但并没有什么帮助,因为我无法将搜索范围缩小到这样的区域(模板图像可能位于原始图像上的任何位置)。 对。但是在模板本身中存在透明的像素(即不应该在模板ROI中)和不透明的像素(即应该在模板ROI中)。可能发生的最糟糕的事情(正如@Utkarsh Shinha 所说,您必须编写自己的模板匹配函数来忽略不在 ROI 中的像素)。 查看示例图像。透明区域绝不是矩形,ROI是矩形。 carlosdc,你没看懂问题。以上是关于OpenCV 模板匹配和透明度的主要内容,如果未能解决你的问题,请参考以下文章