了解和评估模板匹配方法 - python

OpenCV具有matchTemplate()函数,该函数通过在输出上滑动模板输入并生成与匹配项对应的数组输出来进行操作。

在哪里可以了解有关如何解释六个TemplateMatchModes的更多信息?

我已经阅读并实现了基于tutorial的代码,但是除了理解为匹配找到一个TM_SQDIFF的最小结果而为其余的最大值寻找一个代码之外,我不知道如何解释不同的方法,以及一个人会选择一个而不是另一个的情况。

例如(取自本教程)

res = cv.matchTemplate(img_gray, template, cv.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold)

R(x,y)= ∑x′,y′ (T′(x′,y′) ⋅ I′(x+x′,y+y′))
        −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−-------------
       sqrt(∑x′,y′ T′(x′,y′)^2 ⋅ ∑x′,y′ I′(x+x′,y+y′)^2)

(摘自文档页面;不确定如何进行公式格式化)

我推断TM_CCOEFF_NORMED将返回0到1之间的值,并且0.8阈值是任意的,但这只是假设。

是否需要更深入地研究在线方程式,针对标准数据集的性能度量或有关不同模式以及何时以及为何使用一种模式的学术论文?

参考方案

所有模板匹配模式都可以粗略地分类为密集(在像素方向上)相似性度量,或者等效但相反地,图像之间的距离度量。

通常,您将有两张图像,并且想要以某种方式进行比较。模板匹配并不能直接帮助您匹配缩放,旋转或扭曲的对象。模板匹配严格涉及精确测量两个图像的相似度。但是,此处使用的实际度量标准在计算机视觉中得到了广泛使用,包括查找图像之间的转换……只是通常还会进行更复杂的步骤(例如梯度下降以找到最佳的转换参数)。

距离度量有很多选择,并且根据应用程序的不同,它们通常具有优缺点。

绝对差之和(SAD)

首先,最基本的距离度量只是两个值之间的绝对差,即d(x, y) = abs(x - y)。对于图像,将其从单个值扩展的简单方法是将所有这些距离相加,逐个像素,从而得出绝对差之和(SAD)度量;它也称为曼哈顿距离或出租车距离,它定义了L1范数。令人讨厌的是,这并不是作为OpenCV模板匹配模式之一实现的,但是在本次讨论中,与SSD进行比较仍然很重要。

在模板匹配方案中,您可以沿着多个位置滑动模板,然后简单地找出差异最小的位置。这等效于询问数组[1,4,9]中最接近5的索引是什么。您将数组中每个值的绝对差取为5,而索引1的差最小,因此这是最接近的匹配项的位置。当然,在模板匹配中,该值不是5,而是一个数组,并且图像是一个更大的数组。

平方差总和(SSD):TM_SQDIFF

SAD度量标准的一个有趣功能是,它不会对真正的大差异造成任何不利影响,而不会对一堆非常小的差异造成不利影响。假设我们要使用以下向量计算d(a, b)d(a, c)

a = [1, 2, 3]
b = [4, 5, 6]
c = [1, 2, 12]

以元素为单位的绝对差之和,我们看到

SAD(a, b) = 3 + 3 + 3 = 9 = 0 + 0 + 9 = SAD(a, c)

在某些应用程序中,可能没关系。但是在其他应用程序中,您可能希望这两个距离实际上是完全不同的。对差异进行平方处理,而不是取其绝对值,会对与您期望的值相比更远的值进行惩罚-随着值的差异增大,这会使图像距离更远。它将更多地映射到某人可能如何解释估算值的偏离,即使在价值上并没有那么遥远。平方差之和(SSD)等于平方的欧几里得距离,即L2范数的距离函数。使用SSD,我们看到两个距离现在大不相同:

SSD(a, b) = 3^2 + 3^2 + 3^2 = 27 != 81 = 0^2 + 0^2 + 9^2 = SSD(a, c)

您可能会看到L1规范有时被称为鲁棒规范。这是因为单点误差不会比误差本身扩大距离。但是,当然,对于SSD,离群值会使距离更大。因此,如果您的数据容易出现一些非常遥远的值,请注意,SSD可能不是一个好的相似度指标。一个很好的例子可能是比较曝光过度的图像。在图像的某些部分中,您可能只有白色的天空,而其他的根本不是白色的,因此您将在图像之间获得很大的距离。

当比较的两个映像相同时,SAD和SSD的最小距离均为0。它们都总是非负的,因为绝对差或平方差总是非负的。

互相关(CC):TM_CCORR

SAD和SSD都是一般离散指标-因此,它们是采样信号(如图像)的自然考虑因素。然而,互相关也适用于连续信号,因此也适用于模拟信号,这是信号处理中普遍存在的一部分。对于广泛的信号,尝试检测信号中是否存在模板被称为匹配滤波器,您基本上可以将其视为模板匹配的连续模拟。

互相关只是将两个图像相乘。您可以想象,如果两个信号精确对齐,将它们相乘将仅使模板平方。如果它们不是按原样排列的,那么产品将较小。因此,产品最大化的地方就是他们排列最佳的地方。但是,当您将互相关用作不确定的信号的相似性度量时,互相关会出现问题,通常在以下示例中显示。假设您有三个数组:

a = [2, 600, 12]
b = [v, v, v]
c = [2v, 2v, 2v]

大致上,ab以及ac之间没有明显的相关性。通常,ab的关联不应大于与c的关联。但是,它是一个产品,因此是ccorr(a, c) = 2*ccorr(a, b)。因此,这对于尝试在较大图像中查找模板并不理想。而且由于我们要处理具有定义的最大值(图像)的离散数字信号,因此这意味着图像的亮白色斑块基本上总是具有最大的相关性。由于这个问题,TM_CCORR作为模板匹配方法并不是特别有用。

平均移位互相关(Pearson相关系数):TM_CCOEFF

解决与亮斑相关的问题的一种简单方法是在比较信号之前简单地减去均值。这样,简单移位的信号与未移位的信号具有相同的相关性。这凭我们的直觉是有道理的-在一起变化的信号相互关联。

归一化:TM_SQDIFF_NORMEDTM_CCORR_NORMEDTM_CCOEFF_NORMED

OpenCV中的所有方法均被标准化。规范化的目的不是给出置信度/概率,而是给出可以与不同大小的模板或具有不同比例值的模板进行比较的度量。例如,假设我们要查找对象是否在图像中,并且该对象有两个不同的模板。两种不同的模板大小不同。我们可以通过像素数进行归一化,这将比较不同大小的模板。但是,说我的模板实际上在强度上有很大的不同,就像一个模板的像素值方差比另一个模板大得多。通常,在这种情况下,您要做的就是除以标准偏差(与均值平方差之和的平方根)。 OpenCV使用TM_CCOEFF_NORMED方法做到了这一点,因为均值差的平方和是方差,但其他方法并不是均值漂移的,因此缩放只是图像值总和的一种度量。无论哪种方式,结果都是相似的,您希望通过与所使用图像斑块强度有关的缩放比例进行缩放。

其他指标

OpenCV还没有提供其他有用的指标。 Matlab提供SAD以及最大绝对差度量(MaxAD),也称为均匀距离度量,并给出L∞范数。基本上,您采用最大绝对差而不是总和。通常在优化设置中可以看到使用的其他度量,例如首先提出用于立体声匹配的enhanced correlation coefficient,然后通常对其进行扩展以进行对齐。该方法在OpenCV中使用,但不用于模板匹配。您可以在computeECC()findTransformECC()中找到ECC指标。

使用哪种方法?

大多数情况下,您会看到规范和非规范的SSD(TM_SQDIFF_NORMEDTM_SQDIFF),以及使用零归一化互相关/ ZNCC(TM_CCOEFF_NORMED)。有时您可能会看到TM_CCORR_NORMED,但是却很少见。根据我在网上发现的一些lecture notes信息(关于该主题的一些不错的示例和直觉!),Trucco和Verri的CV书指出,一般而言SSD比关联性要好,但是我没有T&V的书来了解为什么他们建议这样做;大概是在真实照片上进行比较。但是,尽管如此,SAD和SSD绝对有用,尤其是在数字图像上。

我不知道任何一种在大多数情况下或某些情况下本质上都更好的示例,我认为这确实取决于您的图像和模板。通常,我会说:如果您正在寻找完全匹配或非常接近完全匹配的内容,请使用SSD。它的速度很快,而且绝对可以映射到您要最小化的内容(模板和图像补丁之间的差异)。在这种情况下,无需进行标准化,这只是增加了开销。如果您有类似的要求,但需要多个模板才能比较,则请标准化SSD。如果您正在寻找匹配项,但您正在处理可能存在曝光或对比度差异的真实照片,则ZNCC的均值漂移和方差均衡可能是最好的。

至于选择正确的阈值,ZNCC或SSD的值根本不是置信度或概率数。如果要选择正确的阈值,则可以采用多种典型方法来测量参数。您可以计算不同阈值的ROC曲线或PR曲线。您可以使用回归来找到最佳参数。您需要标记一些数据,但至少要对一些测试集进行度量,以确保您的选择不是任意的。像往常一样,在充满数据的字段中,您需要确保数据尽可能接近真实示例,并且测试数据涵盖边缘情况和典型图像。

Python sqlite3数据库已锁定 - python

我在Windows上使用Python 3和sqlite3。我正在开发一个使用数据库存储联系人的小型应用程序。我注意到,如果应用程序被强制关闭(通过错误或通过任务管理器结束),则会收到sqlite3错误(sqlite3.OperationalError:数据库已锁定)。我想这是因为在应用程序关闭之前,我没有正确关闭数据库连接。我已经试过了: connectio…

Python:集群作业管理 - python

我在具有两个阶段的计算群集(Slurm)上运行python脚本,它们是顺序的。我编写了两个python脚本,一个用于阶段1,另一个用于阶段2。每天早上,我检查所有第1阶段的工作是否都以视觉方式完成。只有这样,我才开始第二阶段。通过在单个python脚本中组合所有阶段和作业管理,是否有一种更优雅/自动化的方法?我如何知道工作是否完成?工作流程类似于以下内容:w…

Python-Excel导出 - python

我有以下代码:import pandas as pd import requests from bs4 import BeautifulSoup res = requests.get("https://www.bankier.pl/gielda/notowania/akcje") soup = BeautifulSoup(res.cont…

Python:传递记录器是个好主意吗? - python

我的Web服务器的API日志如下:started started succeeded failed 那是同时收到的两个请求。很难说哪一个成功或失败。为了彼此分离请求,我为每个请求创建了一个随机数,并将其用作记录器的名称logger = logging.getLogger(random_number) 日志变成[111] started [222] start…

Python pytz时区函数返回的时区为9分钟 - python

由于某些原因,我无法从以下代码中找出原因:>>> from pytz import timezone >>> timezone('America/Chicago') 我得到:<DstTzInfo 'America/Chicago' LMT-1 day, 18:09:00 STD…