图像Python的滚动统计

图像Python的滚动统计,python,numpy,scipy,imagefilter,Python,Numpy,Scipy,Imagefilter,我需要根据用户定义的2D窗口块计算图像的局部统计信息。统计数据包括:均值、方差、偏斜、峰度。我需要遍历图像的每个像素,根据窗口大小找到相邻像素 我使用的代码是: scipy.ndimage.generic_filter(array,numpy.var,size=3) 但是通过这种方式的性能非常低。我甚至尝试了跨步numpy,但也没有显示出太大的差异(无法计算偏度和峰度)。我对Cython不熟悉,所以我没有冒险去做那个选择。 那么,没有Cython还有其他方法可以实现这一点吗?问题是通用过滤器(

我需要根据用户定义的2D窗口块计算图像的局部统计信息。统计数据包括:均值、方差、偏斜、峰度。我需要遍历图像的每个像素,根据窗口大小找到相邻像素

我使用的代码是:

scipy.ndimage.generic_filter(array,numpy.var,size=3)
但是通过这种方式的性能非常低。我甚至尝试了跨步numpy,但也没有显示出太大的差异(无法计算偏度和峰度)。我对Cython不熟悉,所以我没有冒险去做那个选择。
那么,没有Cython还有其他方法可以实现这一点吗?

问题是
通用过滤器()
不能假设过滤器沿
x
y
轴可分离。因此,它必须作为一个真正的2D过滤器而不是一系列的两个1D过滤器运行,因此运行时会慢得多

平均过滤器和(我认为)等效于
统一过滤器()
,如果您阅读文档,它是作为一系列两个1d统一过滤器实现的

我通过这个代码块比较了定时:

import numpy as np
from scipy import ndimage as ndi
from scipy import misc
baboonfile = '/Users/curt/Downloads/BaboonRGB.jpg'  #local download of http://read.pudn.com/downloads169/sourcecode/graph/texture_mapping/776733/Picture/BaboonRGB__.jpg
im = misc.imread(baboonfile)

meanfilt2D = ndi.generic_filter(im, np.mean, size=[3, 3, 1])
%timeit meanfilt2D = ndi.generic_filter(im, np.mean, size=[3, 3, 1])
print meanfilt2D.shape

meanfiltU = ndi.uniform_filter(im, size=[3, 3, 1])
%timeit meanfiltU = ndi.uniform_filter(im, size=[3, 3, 1])
print meanfiltU.shape
该块的输出为:

1 loops, best of 3: 5.22 s per loop
(512, 512, 3)
100 loops, best of 3: 11.8 ms per loop
(512, 512, 3)
因此,真正的二维
generic_filter()
对于一个小图像需要5秒钟,而双通道1D
uniform_filter()
只需要几毫秒。(注意:差分图像meanfilt2D meanfiltU不是相同的零,但最大元素为2;我认为差异是由舍入和用于
im
的不精确数据类型(
uint8
)造成的)


对于方差和其他过滤器,您应该看到哪个答案是高度相关的问题。

原因
uniform\u filter()
generic\u filter()
要快得多,这是由于Python——对于
generic\u filter()
,每个像素都会调用Python,而对于
uniform\u filter()
,整个图像在本机代码中处理。(我发现OpenCV的
boxFilter()
甚至比
uniform\u filter()
还要快,请参见“窗口差异”问题。)

在本答案的其余部分中,我将展示如何使用
统一过滤器()
进行倾斜计算,这将大大加快基于
通用过滤器()
的版本,例如:

import scipy.ndimage as ndimage, scipy.stats as st
ndimage.generic_filter(img, st.skew, size=(1,5))
SciPy的
st.skew()
(例如,请参见)似乎将倾斜计算为

m3 / m2**1.5
式中,
m3=E[(X-m)**3]
(第三中心力矩)、
m2=E[(X-m)**2]
(方差)和
m=E[X]
(平均值)

要使用
uniform_filter()
,必须根据原始力矩来编写,例如
m3p=E[X**3]
m2p=E[X**2]
(通常使用基本符号来区分原始力矩和中心力矩):

(如果我的“…”跳过太多,这就是m2的全部推导。)然后可以使用
uniform\u filter()
(或者
boxFilter()
实现

generic_filter()
相比,
winSkew()
在我的机器上的以下示例中提供了654倍的加速:

In [185]: img = np.random.randint(0, 256, (500,500)).astype(np.float)

In [186]: %timeit ndimage.generic_filter(img, st.skew, size=(1,5))
1 loops, best of 3: 14.2 s per loop

In [188]: %timeit winSkew(img, (1,5))
10 loops, best of 3: 21.7 ms per loop
两种计算结果基本相同:

In [190]: np.allclose(winSkew(img, (1,5)), ndimage.generic_filter(img, st.skew, size=(1,5)))
Out[190]: True

峰度计算的代码也可以用同样的方法推导出来。

谢谢。这确实加快了方差和均值的计算,但我仍然需要一种方法来加快偏度和峰度的计算。Numpy不支持它们,并且它们不能应用于STERPS输出,因为scipy.stats.skew&kurtosis支持单轴上的应用程序
In [185]: img = np.random.randint(0, 256, (500,500)).astype(np.float)

In [186]: %timeit ndimage.generic_filter(img, st.skew, size=(1,5))
1 loops, best of 3: 14.2 s per loop

In [188]: %timeit winSkew(img, (1,5))
10 loops, best of 3: 21.7 ms per loop
In [190]: np.allclose(winSkew(img, (1,5)), ndimage.generic_filter(img, st.skew, size=(1,5)))
Out[190]: True