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
これは、辺の長さが奇数になると機能しませんが、そのような場合のダウンサンプリングをどのように処理するかに応じて、ピクセルの完全な行(または列)を取り除き、形状を変更できるはずです。 image to (rows // 2, 2, cols // 2, 2, planes)
、つまりimg[r, :, c, :, p]
、新しいピクセル値を取得するために補間する値の2x2行列です。