python自定义函数求差_计算均方、绝对偏差和自定义相似度度量Python/NumPy

导入模块

首先,让我们导入所有相关模块/函数,这些模块/函数将在本文列出的各种方法中使用-from skimage.util import view_as_windows

from skimage.feature import match_template

import cv2

from cv2 import matchTemplate as cv2m

from scipy.ndimage.filters import uniform_filter as unif2d

from scipy.signal import convolve2d as conv2

A、 基于视图的MAD、MSD方法

基于Skimage的计算方法mean absolute deviation:

{{a1}然后使用平均值来计算}

^{pr2}$

使用scikit image获取滑动4D视图数组,然后使用^{}进行平方平均计算-def skimage_views_MAD_v2(img, tmpl):

subs = np.abs(view_as_windows(img, tmpl.shape) - tmpl)

return np.einsum('ijkl->ij',subs)/float(tmpl.size)

基于Skimage的计算方法mean squared deviation:

使用类似的技术,我们将有两种方法来处理mean squared deviation-def skimage_views_MSD_v1(img, tmpl):

return ((view_as_windows(img, tmpl.shape) - tmpl)**2).mean(axis=(2,3))

def skimage_views_MSD_v2(img, tmpl):

subs = view_as_windows(img, tmpl.shape) - tmpl

return np.einsum('ijkl,ijkl->ij',subs, subs)/float(tmpl.size)

B、 基于卷积的MSD方法

基于卷积的计算方法mean squared deviations:

Convolution可用于计算均方偏差,但需稍加调整。对于方差平方和的情况,我们在每个窗口中执行元素减法,然后将每个减法平方,然后将所有这些减法相加。在

让我们考虑一个1D示例来进一步了解-a : [a1, a2, a3, a4, a5, a6, a7, a8] # Image array

b : [b1, b2, b3] # Template array

对于第一个窗口操作,我们需要:(a1-b1)**2 + (a2-b2)**2 + (a3-b3)**2

让我们使用(a-b)**2公式:(a - b)**2 = a**2 - 2*a*b +b**2

因此,对于第一个窗口:(a1**2 - 2*a1*b1 +b1**2) + (a2**2 - 2*a2*b2 +b2**2) + (a3**2 - 2*a3*b3 +b3**2)

同样,对于第二个窗口:(a2**2 - 2*a2*b1 +b1**2) + (a3**2 - 2*a3*b2 +b2**2) + (a4**2 - 2*a4*b3 +b3**2)

等等。在

所以,这些计算有三个部分-滑动窗中a的平方和求和。

b的平方和那些的总和。这在所有窗口中保持不变。

最后一块拼图是:(2*a1*b1, 2*a2*b2, 2*a3*b3),(2*a2*b1, 2*a3*b2, 2*a4*b3)等等,对于第一个窗口,第二个窗口等等。{{{14}的乘法{在这个窗口中,每个元素的{14}都可以在这个方向上,用cda4}计算每个元素的和。

将这些思想扩展到2D情况,并使用Scipy's convolve2d和{},我们将有两种方法来计算mean squared deviations,如下-def convolution_MSD(img, tmpl):

n = tmpl.shape[0]

sums = conv2(img**2,np.ones((n,n)),'valid')

out = sums + (tmpl**2).sum() -2*conv2(img,tmpl[::-1,::-1],'valid')

return out/(n*n)

def uniform_filter_MSD(img, tmpl):

n = tmpl.shape[0]

hWSZ = (n-1)//2

sums = unif2d(img.astype(float)**2,size=(n,n))[hWSZ:-hWSZ,hWSZ:-hWSZ]

out = sums + (tmpl**2).mean() -2*conv2(img,tmpl[::-1,::-1],'valid')/float(n*n)

return out

C、 基于Skimage的NCC方法

基于Skimage的计算方法normalized cross-correlation:def skimage_match_template(img, tmpl):

return match_template(img, tmpl)

请注意,由于这些是互相关值,图像和模板之间的紧密性将以高输出值为特征。在

D、 基于OpenCV的多种相似性度量方法

OpenCV提供了各种^{}分类模板的方法-def opencv_generic(img, tmpl, method_string ='SQDIFF'):

# Methods :

# 'CCOEFF' : Correlation coefficient

# 'CCOEFF_NORMED' : Correlation coefficient normalized

# 'CCORR' : Cross-correlation

# 'CCORR_NORMED' : Cross-correlation normalized

# 'SQDIFF' : Squared differences

# 'SQDIFF_NORMED' : Squared differences normalized

method = eval('cv2.TM_' + method_string)

return cv2m(img.astype('uint8'),tmpl.astype('uint8'),method)

E、 基于视图的方法:自定义函数

我们可以使用本文前面所示的4D视图,并沿着最后两个轴执行自定义的相似性度量。在

因此,我们将滑动窗口作为一个4D数组,如前所述-img_4D = view_as_windows(img, tmpl.shape)

请注意,作为输入图像的视图,它将不再消耗内存。但后面的操作会根据这些操作本身进行复制。比较操作将导致更少的内存占用(确切地说,在Linux上是8倍)。在

然后,我们在img_4D和{}之间执行预期的操作,这在线性映射操作中会导致^{}后面的另一个4D数组。我们称之为img_sub。下一步,最有可能的是,我们将进行一些还原操作,以得到一个2D输出。同样,在大多数情况下,这里可以使用^{}中的一个。我们需要沿着img_sub上的最后两个轴使用这个ufunc。同样,许多ufunc允许我们一次在多个轴上工作。例如,前面我们一次性地沿着最后两个轴使用mean计算。否则,我们需要沿着这两个轴一个接一个地操作。在

示例

作为n关于如何使用的示例,让我们考虑一个自定义函数:mean((img_W**tmpl)*tmpl - 2*img*tmpl**2)

这里,我们有img_W作为img的滑动窗口,tmpl通常是在{}的高度和宽度上滑动的模板。在

通过两个嵌套循环实现,我们将拥有:def func1(a,b):

m1,n1 = a.shape

m2,n2 = b.shape

mo,no = m1-m2+1, n1-n2+1

out = np.empty((mo,no))

for i in range(mo):

for j in range(no):

out[i,j] = ((a[i:i+m2,j:j+n2]**2)*b - 2*a[i:i+m2,j:j+n2]*(b**2)).mean()

return out

现在,使用view_as_windows,我们将得到一个矢量化的解决方案:def func2(a,b):

a4D = view_as_windows(img, tmpl.shape)

return ((a4D**2)*b - 2*a4D*(b**2)).mean(axis=(2,3))

运行时测试-In [89]: # Sample image(a) and template(b)

...: a = np.random.randint(4,9,(50,100))

...: b = np.random.randint(2,9,(15,15))

...:

In [90]: %timeit func1(a,b)

1 loops, best of 3: 147 ms per loop

In [91]: %timeit func2(a,b)

100 loops, best of 3: 17.8 ms per loop

基准:均方偏差

适当大小的数据集:In [94]: # Inputs

...: img = np.random.randint(0,255,(50,100))

...: tmpl = np.random.randint(0,255,(15,15))

...:

In [95]: out1 = skimage_views_MSD_v1(img, tmpl)

...: out2 = skimage_views_MSD_v2(img, tmpl)

...: out3 = convolution_MSD(img, tmpl)

...: out4 = uniform_filter_MSD(img, tmpl)

...: out5 = opencv_generic(img, tmpl, 'SQDIFF')/tmpl.size

...:

...: print np.allclose(out1, out2)

...: print np.allclose(out1, out3)

...: print np.allclose(out1, out4)

...: print np.allclose(out1, out5)

...:

True

True

True

True

In [96]: %timeit skimage_views_MSD_v1(img, tmpl)

...: %timeit skimage_views_MSD_v2(img, tmpl)

...: %timeit convolution_MSD(img, tmpl)

...: %timeit uniform_filter_MSD(img, tmpl)

...: %timeit opencv_generic(img, tmpl, 'SQDIFF')/tmpl.size

...:

100 loops, best of 3: 8.49 ms per loop

100 loops, best of 3: 3.87 ms per loop

100 loops, best of 3: 5.96 ms per loop

100 loops, best of 3: 3.25 ms per loop

10000 loops, best of 3: 201 µs per loop

对于更大的数据量,根据可用的系统RAM,我们可能不得不返回到留下明显内存占用的views方法以外的方法。在

让我们用剩下的方法测试更大的数据-In [97]: # Inputs

...: img = np.random.randint(0,255,(500,1000))

...: tmpl = np.random.randint(0,255,(15,15))

...:

In [98]: %timeit convolution_MSD(img, tmpl)

...: %timeit uniform_filter_MSD(img, tmpl)

...: %timeit opencv_generic(img, tmpl, 'SQDIFF')/tmpl.size

...:

1 loops, best of 3: 910 ms per loop

1 loops, best of 3: 483 ms per loop

100 loops, best of 3: 16.1 ms per loop

摘要当使用已知的相似性度量时,即基于OpenCV的模板匹配方法列出的六种方法之一,如果我们可以访问OpenCV,那将是最好的方法。

在没有OpenCV的情况下,对于均方偏差这样的特殊情况,我们可以利用卷积来获得相当有效的方法。

对于通用/自定义函数和适当大小的数据大小,我们可以查看4D视图以获得有效的矢量化解决方案。对于大型数据,我们可能希望使用一个循环并使用3D视图而不是4D,以减少内存占用。对于真正大的循环,您可能需要回到两个嵌套的循环中。

你可能感兴趣的:(python自定义函数求差)