计算方差图像python

Tho*_*mas 5 python numpy image filter scipy

有没有一种简单的方法可以使用Python/NumPy/Scipy计算图像上的运行方差滤镜?通过运行方差图像,I表示计算图像中每个子窗口I的和((I - mean(I))^ 2)/ nPixels的结果.

由于图像非常大(12000x12000像素),我想避免在格式之间转换数组的开销,只是为了能够使用不同的库然后转换回来.

我想我可以通过使用类似的东西找到平均值来手动执行此操作

kernel = np.ones((winSize, winSize))/winSize**2
image_mean = scipy.ndimage.convolve(image, kernel)
diff = (image - image_mean)**2
# Calculate sum over winSize*winSize sub-images
# Subsample result
Run Code Online (Sandbox Code Playgroud)

但是从matlab获得类似stdfilt-function的东西要好得多.

任何人都可以指向具有此功能的库的方向并支持numpy数组,或提示/提供在NumPy/SciPy中执行此操作的方法吗?

Jai*_*ime 5

您可以numpy.lib.stride_tricks.as_strided用来获取图像的窗口视图:

import numpy as np
from numpy.lib.stride_tricks import as_strided

rows, cols = 500, 500
win_rows, win_cols = 5, 5

img = np.random.rand(rows, cols)

win_img = as_strided(img, shape=(rows-win_rows+1, cols-win_cols+1,
                                 win_rows, win_cols),
                     strides=img.strides*2)
Run Code Online (Sandbox Code Playgroud)

现在win_img[i, j](win_rows, win_cols)左上角在position 的数组[i, j]

>>> img[100:105, 100:105]
array([[ 0.34150754,  0.17888323,  0.67222354,  0.9020784 ,  0.48826682],
       [ 0.68451774,  0.14887515,  0.44892615,  0.33352743,  0.22090103],
       [ 0.41114758,  0.82608407,  0.77190533,  0.42830363,  0.57300759],
       [ 0.68435626,  0.94874394,  0.55238567,  0.40367885,  0.42955156],
       [ 0.59359203,  0.62237553,  0.58428725,  0.58608119,  0.29157555]])
>>> win_img[100,100]
array([[ 0.34150754,  0.17888323,  0.67222354,  0.9020784 ,  0.48826682],
       [ 0.68451774,  0.14887515,  0.44892615,  0.33352743,  0.22090103],
       [ 0.41114758,  0.82608407,  0.77190533,  0.42830363,  0.57300759],
       [ 0.68435626,  0.94874394,  0.55238567,  0.40367885,  0.42955156],
       [ 0.59359203,  0.62237553,  0.58428725,  0.58608119,  0.29157555]])
Run Code Online (Sandbox Code Playgroud)

但是,您必须小心,不要将窗口的图像视图转换为窗口的窗口副本:在我的示例中,这将需要25倍的存储空间。我相信numpy 1.7可以让您选择多个轴,因此您可以简单地执行以下操作:

>>> np.var(win_img, axis=(-1, -2))
Run Code Online (Sandbox Code Playgroud)

我坚持使用numpy 1.6.2,因此无法对其进行测试。如果我没记错数学的话,另一个选择可能会因窗口不那么大而失败,那就是:

>>> win_mean = np.sum(np.sum(win_img, axis=-1), axis=-1)/win_rows/win_cols
>>> win_sqr_mean = np.sum(np.sum(win_img**2, axis=-1), axis=-1)/win_rows/win_cols
>>> win_var = win_sqr_mean - win_mean**2
Run Code Online (Sandbox Code Playgroud)

现在win_var是形状的数组

>>> win_var.shape
(496, 496)
Run Code Online (Sandbox Code Playgroud)

win_var[i, j]保持(5, 5)窗口的左上角为的方差[i, j]


2di*_*com 5

更简单的解决方案也更快:使用SciPy ndimage.uniform_filter

import numpy as np
from scipy import ndimage 
rows, cols = 500, 500
win_rows, win_cols = 5, 5

img = np.random.rand(rows, cols)
win_mean = ndimage.uniform_filter(img, (win_rows, win_cols))
win_sqr_mean = ndimage.uniform_filter(img**2, (win_rows, win_cols))
win_var = win_sqr_mean - win_mean**2
Run Code Online (Sandbox Code Playgroud)

"步幅技巧"是一个很好的技巧,但是速度慢4而且不那么可读.在generic_filter比慢迈进20倍...