我已经使用纯Python编写了一个函数来模糊我提供的任何图像。现在,我想使用NumPy并删除所有for
循环。
def blur_image(src, dst):
(h, w, c) = src.shape
for x in range(h-1):
for y in range(w-1):
for z in range(c):
if x != 0 or y != 0:
dst[x, y, z] = (src[x, y, z]
+ src[x-1, y, z]
+ src[x+1, y, z]
+ src[x, y-1, z]
+ src[x, y+1, z]
+ src[x-1, y-1, z]
+ src[x-1, y+1, z]
+ src[x+1, y-1, z]
+ src[x+1, y+1, z]) / 9
if x == 0:
dst[x, y, z] = (src[x, y, z]
+ src[x, y, z]
+ src[x+1, y, z]
+ src[x, y-1, z]
+ src[x, y+1, z]
+ src[x, y-1, z]
+ src[x, y+1, z]
+ src[x+1, y-1, z]
+ src[x+1, y+1, z]) / 9
if y == 0:
dst[x, y, z] = (src[x, y, z]
+ src[x-1, y, z]
+ src[x+1, y, z]
+ src[x, y, z]
+ src[x, y+1, z]
+ src[x-1, y, z]
+ src[x-1, y+1, z]
+ src[x+1, y, z]
+ src[x+1, y+1, z]) / 9
return dst
如何使用NumPy改进此代码?最好的情况是删除所有for
循环吗?有提示吗?
您可以使用numba包的vectorize属性,如下所示。
numba使用cpython编译python代码,这也使其高效。
如果您不想使用numba,也可以使用np.vectorize(func)
import numba as nb
@nb.vectorize
def blur_image(src, dst):
...
# now you can use this function with numpy array like this
blur_image(nparray)
我假设您想加快您的功能。最简单且可能也是最快的方法是使用像Cython或Numba这样的编译器。
问题也令人尴尬地平行。
实施例
import numpy as np
import numba as nb
@nb.njit(error_model="numpy",parallel=True)
def blur_image_nb(src, dst):
(h, w, c) = src.shape
for x in nb.prange(h-1):
for y in range(w-1):
for z in range(c):
if x != 0 or y != 0:
dst[x, y, z] = (src[x, y, z]
+ src[x-1, y, z]
+ src[x+1, y, z]
+ src[x, y-1, z]
+ src[x, y+1, z]
+ src[x-1, y-1, z]
+ src[x-1, y+1, z]
+ src[x+1, y-1, z]
+ src[x+1, y+1, z]) / 9
if x == 0:
dst[x, y, z] = (src[x, y, z]
+ src[x, y, z]
+ src[x+1, y, z]
+ src[x, y-1, z]
+ src[x, y+1, z]
+ src[x, y-1, z]
+ src[x, y+1, z]
+ src[x+1, y-1, z]
+ src[x+1, y+1, z]) / 9
if y == 0:
dst[x, y, z] = (src[x, y, z]
+ src[x-1, y, z]
+ src[x+1, y, z]
+ src[x, y, z]
+ src[x, y+1, z]
+ src[x-1, y, z]
+ src[x-1, y+1, z]
+ src[x+1, y, z]
+ src[x+1, y+1, z]) / 9
return dst
计时
src=np.random.rand(1024,1024,3)
dst=np.empty((1024,1024,3))
%timeit blur_image(src, dst)
8.08 s ± 52.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit blur_image_nb(src, dst)
5.19 ms ± 954 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
如果我正确阅读了您的代码,则说明您正在使用3×3棚车过滤器进行过滤。如果您关心性能,那么为此使用现有库可能是个好主意,因为它比您可以轻松实现的任何东西都要优化得多。
例如,您正在做的事可以通过卷积来实现,在scipy.signal
中可用。因此,您可以为每个通道执行此操作,然后堆叠结果数组:
scipy.signal
import numpy as np
import scipy.signal as ss
arr = np.random.random((100, 100)) # Some fake data.
kernel = np.ones((3, 3)) / 9 # The 'boxcar'.
ss.convolve(arr, kernel, mode='same')
中也可以使用模糊:
PIL
[还有很多其他方法,包括在傅立叶空间(PIL
)中进行。
[这些其他方法的一个不错的特性是,它们不会将滤波器设计硬编码到代码中,因此尝试使用另一个内核(例如高斯程序)很容易。