目前,我已经编写了一些插入管道的Python代码。
传入的数据形状为numpy数组(1,512,19,25)。我使用scipy.ndimage.interpolation.zoom
使阵列变形(1,512,38,50)。这可以通过一次调用函数来完成。基本上,它将每个(19,25)的大小调整为大小(38,50)。
稍后在代码中,当数据以另一种方式移动时,不同的数据将再次调整为另一个方向(38,50)到(19,25)。
一切都按实施方式运作,但我发现这确实很慢。例如,我测试了scipy.ndimage.interpolation.zoom
函数来调整图像文件的大小,它比Matlab的imresize
函数慢。
在Python中有哪些更快的方法?
答案 0 :(得分:0)
检查https://python-pillow.org/pillow-perf/中的基准
TL; DR:在大多数情况下,Python中最快的方法是使用pillow-simd。
答案 1 :(得分:0)
TLDR; 查看Skimage的pyramid_gaussian。在(512,512)的单个图像上,它显示了0.3M倍的加速。 (163 ms / 471 ns = 346072)。 Pillow-SIMD会super-fast进行重新采样/调整大小,但要求您先卸载PIL Pillow,然后再安装。它使用并行处理(单指令,多数据-SIMD)和更好的算法,例如用顺序盒替换基于卷积的高斯模糊。设置单独的venv
后,建议将其用于生产环境。
有多种方式对图像进行上采样和下采样。我将为我使用的方法添加一些基准。当我遇到更多方法时,我将不断更新此答案,以便可以将其用作SO上其他参考。
#Utility function for plotting original, upsampled, and downsampled image
def plotit(img, up, down):
fig, axes = plt.subplots(1,3, figsize=(10,15))
axes[0].imshow(img)
axes[1].imshow(up)
axes[2].imshow(down)
axes[0].title.set_text('Original')
axes[1].title.set_text('Upsample')
axes[2].title.set_text('Downsample')
IIUC,这有点像您的管道-
from scipy.ndimage import zoom
from skimage.data import camera
img = camera() #(512,512)
up = zoom(img,2) #upsample image
#some code
...
down = zoom(up,0.5) #downsample the upsampled image
plotit(img, up, down)
方法和基准
(in no specific order)
1。 Scipy zoom(order = 3)
使用给定顺序的样条插值缩放数组,在这种情况下,默认值为order = 3。
%%timeit
#from scipy.ndimage import zoom
up = zoom(img,2)
down = zoom(up,0.5)
#163 ms ± 12.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
2。 Scipy zoom(order = 0)
使用给定阶数的样条插值对数组进行缩放,在这种情况下,阶数= 0。
%%timeit
#from scipy.ndimage import zoom
up = zoom(img,2, order=0)
down = zoom(up,0.5, order=0)
#18.7 ms ± 950 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3。 Skimage pyramid_gaussian
在高斯金字塔中,使用高斯平均(高斯模糊)对后续图像进行加权并进行缩放。对图像应用高斯模糊与将图像与高斯函数卷积相同。模糊程度取决于标准偏差大小(sigma)。
%%timeit
#from skimage.transform import import pyramid_gaussian
up = pyramid_gaussian(img,2)
down = pyramid_gaussian(up,0.5)
#471 ns ± 30.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
4。 Skimage pyramid_expand和pyramid_reduce
图像金字塔是一种多尺度图像表示,其中图像要进行重复的平滑和二次采样。第一个函数先对图像进行平滑处理,然后再对图像进行升采样,而第二个函数执行相同的操作,但对图像进行降采样,默认情况下,这两个函数都使用样条线order = 1。
%%timeit
#from skimage.transform import import pyramid_expand, pyramid_reduce
up = pyramid_expand(img,2)
down = pyramid_reduce(up,2)
#120 ms ± 3.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
5。 Skimage rescale
按一定比例缩放图像。执行样条插值(默认情况下,order = 1)以放大或缩小N维图像。请注意,缩小图像尺寸时应启用抗锯齿功能,以免产生锯齿失真。
%%timeit
#from skimage.transform import import rescale
up = rescale(img,2)
down = rescale(up,0.5)
#83 ms ± 3.69 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
6。具有最近像素resize的PIL filter用于重采样
返回此图像的调整大小的副本。从输入图像中选择一个最近的像素。忽略所有其他输入像素。
%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.NEAREST)
down = up.resize((up.width//2, up.height//2),resample=Image.NEAREST)
#704 µs ± 29.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
7。 PIL resize和BILINEAR filter用于重采样
返回此图像的调整大小的副本。对于调整大小,在可能影响输出值的所有像素上使用线性插值计算输出像素值。对于其他转换,将在输入图像的2x2环境中使用线性插值。
%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.BILINEAR)
down = up.resize((up.width//2, up.height//2),resample=Image.BILINEAR)
#10.2 ms ± 877 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
8。 PIL resize和BICUBIC filter用于重采样
返回此图像的调整大小的副本。对于调整大小,对所有可能影响输出值的像素使用三次插值计算输出像素值。对于其他变换,使用输入图像中4x4环境上的三次插值。
%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.BICUBIC)
down = up.resize((up.width//2, up.height//2),resample=Image.BICUBIC)
#12.3 ms ± 326 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9。与Lanczos resize进行PIL filter进行重采样
返回此图像的调整大小的副本。在所有可能影响输出值的像素上,使用高质量的Lanczos滤波器(截短的sinc)计算输出像素值。
%%timeit
#from PIL import Image
im = Image.fromarray(img)
up = im.resize((im.width*2, im.height*2),resample=Image.LANCZOS)
down = up.resize((up.width//2, up.height//2),resample=Image.LANCZOS)
#15.7 ms ± 184 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)