矢量化模糊图像的Python函数

问题描述 投票:1回答:3

我已经使用纯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循环吗?有提示吗?

python python-2.7 numpy vectorization slice
3个回答
0
投票

您可以使用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)


0
投票

简单编译

我假设您想加快您的功能。最简单且可能也是最快的方法是使用像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)

0
投票

如果我正确阅读了您的代码,则说明您正在使用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)中进行。

[这些其他方法的一个不错的特性是,它们不会将滤波器设计硬编码到代码中,因此尝试使用另一个内核(例如高斯程序)很容易。

© www.soinside.com 2019 - 2024. All rights reserved.