矢量化模糊图像的Python函数
我已经使用纯Python制作了一个函数来模糊我给出的任何图像。现在我想使用NumPy并删除循环的所有矢量化模糊图像的Python函数,python,numpy,image-processing,vectorization,Python,Numpy,Image Processing,Vectorization,我已经使用纯Python制作了一个函数来模糊我给出的任何图像。现在我想使用NumPy并删除循环的所有 def模糊图像(src、dst): (h,w,c)=src形状 对于范围(h-1)内的x: 对于范围内的y(w-1): 对于范围(c)内的z: 如果x!=0或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] +sr
def模糊图像(src、dst):
(h,w,c)=src形状
对于范围(h-1)内的x:
对于范围内的y(w-1):
对于范围(c)内的z:
如果x!=0或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
如果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
如果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
返回dst
如何使用NumPy使此代码变得更好?最好的情况是删除所有for
循环?有什么建议吗
编辑:我试图在没有任何库帮助我模糊图像的情况下解决这个问题。我使用纯python对其进行模糊处理,现在寻找一些技巧,以便所有计算量大的位都使用numpy数组。没有很多使用numpy的经验://只需编译它
我假设你想加速你的功能。最简单也是最快的方法是使用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
编辑
当然,也有一些简单的优化是可能的,比如不必要的除以常量值。也可以乘以只计算一次的因子
#You can achieve the same with fastmath=True
#Divisions are quite costly
@nb.njit(error_model="numpy",parallel=True)
def blur_image_nb_2(src, dst):
(h, w, c) = src.shape
fact=1./9.
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]) *fact
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]) *fact
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]) *fact
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)
%timeit blur_image_nb_2(src, dst)
3.13 ms ± 167 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
#Just for comparison
%timeit res=np.copy(src)
11.1 ms ± 28.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit np.copyto(dst, src)
2.44 ms ± 53.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
import numpy as np
from PIL import Image, ImageFilter
import scipy.signal as ss
src=(np.random.rand(1024,1024,3)*255).astype(np.uint8)
img = Image.fromarray(src.astype(np.uint8))
%timeit img.filter(ImageFilter.BoxBlur(radius=3))
16.1 ms ± 65 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
kernel = np.ones((3, 3)) / 9 # The 'boxcar'.
#3x in a example where src.shape[2]==3
%timeit ss.convolve(src[:,:,0], kernel, mode='same')
76.6 ms ± 16.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
结论
通常情况下,您只需使用已经可用的函数,如他的答案中所示的@kwinkunks,但简单地编译函数会显示出比PIL更好的性能(PIL在数据类型方面也有一些限制)和更一般的卷积。如果我正确地阅读了您的代码,您正在描述使用3×3 boxcar过滤器进行过滤。如果您关心性能,那么使用现有库来实现这一点可能是一个好主意,因为它将比您可以轻松实现的任何功能都要优化
例如,您所做的可以通过卷积来实现,卷积在中提供。因此,您可以对每个通道执行此操作,然后堆叠生成的阵列:
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')
模糊也可在以下位置使用:
还有很多其他的方法可以做到这一点,包括在傅立叶空间()中
这些其他方法的一个很好的特点是,它们不会将过滤器设计硬编码到代码中,因此很容易尝试其他内核,例如高斯核。我想不久前我也做过类似的事情。我解决这个问题的方法是制作一个图像副本,其中每个像素值实际上是围绕中心像素的像素值的3x3数组。然后,您应该能够将所有这些值添加到原始像素值。如果您使用这种方法,可能会有很大帮助。您主要关心的是性能还是如何将其矢量化?另一种可能是利用gpu计算卷积滤波器模糊。这可以使用pyopengl来利用,但不是一个预构建的解决方案。谢谢!我知道有很多不同的库可以为我模糊图像。我只是想找到一种不用所有的图书馆就能做到这一点的方法。并要求一些提示,以帮助我的方式。我没有很多使用numpy的经验:)@Panini所以你想要一个纯numpy(无SciPy)的方式来做吗?你知道NumPy是一个库(建立在许多其他库的基础上),对吗?它的许多功能(例如,np.convolve
)都是一维的,因此存在局限性。所以你必须在一个方向卷积,然后在另一个方向卷积。这有意义吗?为了纯粹的指导目的,而不是为了生产,以下是如何实现具有1D过滤器两个正交通道的2D过滤器:
import numpy as np
from PIL import Image, ImageFilter
arr = np.random.randint(0, 256, size=((100, 100, 3)), dtype=np.uint8)
img = Image.fromarray(arr)
img.filter(ImageFilter.BoxBlur(radius=3))