如何消除循环并使用 numpy reshape?

问题描述 投票:0回答:2

我有以下代码,

import numpy as np
from matplotlib import pyplot as plt
from PIL import Image as im

B = 9
pic = np.array(im.open('portrait.png'))
pic = pic[pic.shape[0] % B:, pic.shape[1] % B:, :3]
reduced, _i, _j = [], 0, 0
for i in range(B, pic.shape[0] + B, B):
    for j in range(B, pic.shape[1] + B, B):
        pix = pic[_i:i, _j:j].reshape(B * B, 3).mean(axis=0)
        reduced.append(pix.astype(np.uint8))
        _j = j
    _i, _j = i, 0
reduced = np.array(reduced)
reduced = reduced.reshape((pic.shape[0] // B, pic.shape[1] // B, 3))
plt.title(reduced.shape)
plt.imshow(reduced)
plt.show()

它本质上是通过图像的

B
块迭代
B
,并通过取它们的平均值将它们变成一个像素。

所以这个,

Van Gogh

变成这样,

我认为这可以通过重塑、沿某个轴取平均值然后再次重塑来以某种方式完成。但我不确定如何取出那个循环。

numpy reshape
2个回答
1
投票

您可以在图像中引入

BxB
块作为额外的轴,然后沿这些轴取平均值:

import numpy as np
from matplotlib import pyplot as plt
from PIL import Image as im

B = 9
pic = np.array(im.open('portrait.png'))

h, w, c = pic.shape
H, W = h - h % B, w - w % B

reduced = (
    pic[-H:,-W:]                             # crop to multiple of block size
        .reshape((H // B, B, W // B, B, c))  # split y and x axes into blocks
        .mean(axis=(1,3))                    # take the mean
        .astype(np.uint8)                    # convert from float
)

plt.title(reduced.shape)
plt.imshow(reduced)
plt.show()

0
投票

如果您不介意使用额外的库,您可以使用

einops
以直接且不言自明的方式实现它,如下所示:

import einops

img = ...
B=9

im_reduced = einops.reduce(img, "(h Bh) (w Bw) C -> h w C", "mean", Bh=B, Bw=B)
© www.soinside.com 2019 - 2024. All rights reserved.