您可以使用一种广为人知的
滑动窗口步幅技巧来加速计算。它在不复制数据的情况下,在数组末尾添加了两个“虚拟维度”,然后对它们进行方差计算。
请注意,在您的代码中,
im[j-w:j+w, ..]
遍历的索引是
j-w,j-w+1,...,j+w-1
,最后一个索引是排除在外的,这可能不是您想要的。此外,方差大于uint8范围,因此您最终会得到整数环绕。
import numpy as np
import time
np.random.seed(1234)
img = (np.random.rand(200, 200)*256).astype(np.uint8)
def sliding_window(a, window, axis=-1):
shape = list(a.shape) + [window]
shape[axis] -= window - 1
if shape[axis] < 0:
raise ValueError("Array too small")
strides = a.strides + (a.strides[axis],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
def sliding_img_var(img, window):
if window <= 0:
raise ValueError("invalid window size")
buf = sliding_window(img, 2*window, 0)
buf = sliding_window(buf, 2*window, 1)
out = np.zeros(img.shape, dtype=np.float32)
np.var(buf[:-1,:-1], axis=(-1,-2), out=out[window:-window,window:-window])
return out
def looping_img_var(im, w):
nx, ny = img.shape
varianceMatrix = np.zeros(im.shape, np.float32)
for i in range(w,nx-w):
for j in range(w,ny-w):
sampleframe = im[j-w:j+w, i-w:i+w]
variance = np.var(sampleframe)
varianceMatrix[j][i] = variance
return varianceMatrix
np.set_printoptions(linewidth=1000, edgeitems=5)
start = time.time()
print(sliding_img_var(img, 1))
time_sliding = time.time() - start
start = time.time()
print(looping_img_var(img, 1))
time_looping = time.time() - start
print("duration: sliding: {0} s, looping: {1} s".format(time_sliding, time_looping))
ndimage.uniform_filter()
代替cv2.boxFilter()
,请参见此答案以获取类似问题的解决方案。对于我在这里使用的示例,OpenCV版本快了4.1倍。 - Ulrich SternwinVar()
转换为winStd()
),只需更改为return np.sqrt(wsqrmean - wmean*wmean)
。 - Ulrich Stern