在numpy中生成图像的Mipmap?
我想问一下,有没有简单的numpy方法可以用双线性过滤来缩小一个二维numpy数组(也就是一张图片)的尺寸?
具体来说,我的数组形状是(width, height, 4)(就像一张rgba格式的图片)。缩小的过程只在“偶数”步进行:也就是说,从(w, h, 4)缩小到(w/2, h/2, 4),再到(w/4, h/4, 4)等等。
我查了很久,但大家似乎都在提到scipy/PIL的imresize方法。
我想尽量减少对python包的依赖,所以只想用numpy。
在我决定用C++来实现之前,我想先在这里确认一下。
1 个回答
3
我觉得在numpy里没有特别的解决方案,不过你应该能在python里高效地实现这个功能。请纠正我,如果我说错了的话。当图像的大小能被2整除时,双线性滤波其实就是把原图的4个像素平均成1个新像素,对吧?如果你的图像大小是2的幂次方,那么下面的代码:
from __future__ import division
import numpy as np
from PIL import Image
def halve_image(image) :
rows, cols, planes = image.shape
image = image.astype('uint16')
image = image.reshape(rows // 2, 2, cols // 2, 2, planes)
image = image.sum(axis=3).sum(axis=1)
return ((image + 2) >> 2).astype('uint8')
def mipmap(image) :
img = image.copy()
rows, cols, planes = image.shape
mipmap = np.zeros((rows, cols * 3 // 2, planes), dtype='uint8')
mipmap[:, :cols, :] = img
row = 0
while rows > 1:
img = halve_image(img)
rows = img.shape[0]
mipmap[row:row + rows, cols:cols + img.shape[1], :] = img
row += rows
return mipmap
img = np.asarray(Image.open('lena.png'))
Image.fromarray(mipmap(img)).save('lena_mipmap.png')
会产生这样的输出:
对于一个512x512的原始图像,它在我的系统上运行时间是:
In [3]: img.shape
Out[3]: (512, 512, 4)
In [4]: %timeit mipmap(img)
10 loops, best of 3: 154 ms per loop
如果边长是奇数的话,这个方法就不适用了。不过,具体要怎么处理这些情况的下采样,你应该可以去掉一整行(或一整列)的像素,然后把图像重新调整为 (rows // 2, 2, cols // 2, 2, planes)
,这样 img[r, :, c, :, p]
就会变成一个2x2的值矩阵,用来插值计算出新的像素值。