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中执行此操作的方法吗?
您可以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]。
更简单的解决方案也更快:使用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倍...