求教 numpy 数组运算简化,去掉 for 循环。。

99 天前
 XIVN1987

代码如下,中间那三行两层 for 循环迭代的代码,是否可以去掉 for 循环??感谢指点。。

def jpeg2png(path, name, mask=(255, 255, 255), limit=32):
    img = Image.open(path)
    
    arr = np.array(img.convert('RGBA'))

    for i in range(arr.shape[0]):
        for j in range(arr.shape[1]):
            arr[i,j,3] = 0x00 if np.all(np.abs(arr[i,j,:3] - mask) < limit) else 0xFF      # alhpa channel

    Image.fromarray(arr).save(f'{name}.png')
1519 次点击
所在节点    Python
4 条回复
xiaotang3011
99 天前
np.where
holy5pb
99 天前
```python
def jpeg2png(path, name, mask=(255, 255, 255), limit=32):
img = Image.open(path)

arr = np.array(img.convert('RGBA'))

# np.where
condition = np.all(np.abs(arr[:, :, :3] - mask) < limit, axis=2)
arr[:, :, 3] = np.where(condition, 0x00, 0xFF) # alpha channel

Image.fromarray(arr).save(f'{name}.png')
```
XIVN1987
99 天前
@holy5pb
试过了,,可以,,感谢大神。。
sampeng
99 天前
是的,可以用 NumPy 的广播功能来去除 for 循环。NumPy 是一个强大的科学计算库,它允许你对整个数组或矩阵进行快速操作,而不需要显式地编写循环。在你的例子中,你可以使用 NumPy 的布尔索引来直接设置 alpha 通道的值。

下面是一个如何用 NumPy 的广播和布尔索引来替换掉 for 循环的例子:

from PIL import Image
import numpy as np

def jpeg2png(path, name, mask=(255, 255, 255), limit=32):
img = Image.open(path)

arr = np.array(img.convert('RGBA'))

# 创建一个布尔掩码,其中接近指定 mask 颜色的像素为 True
mask_arr = np.all(np.abs(arr[:, :, :3] - mask) < limit, axis=-1)

# 设置 alpha 通道为 0 (透明) 在 mask_arr 为 True 的地方,否则设置为 255 (不透明)
arr[:, :, 3] = np.where(mask_arr, 0x00, 0xFF)

Image.fromarray(arr).save(f'{name}.png')

# 使用函数转换图片
jpeg2png('input.jpg', 'output')
在这个改写后的函数中,np.where 函数用于选择性地替换数组中的元素。mask_arr 是一个与输入图像同样形状的布尔数组,它标志了所有需要被设置为透明的像素。np.where 根据 mask_arr 的值来设置 arr 的 alpha 通道,如果 mask_arr 为 True 则设置为 0x00 ,否则设置为 0xFF 。

这种方法比双层 for 循环更有效,因为它利用了 NumPy 的内部优化来处理数组操作,从而可以显著提升性能,特别是在处理大图像时。


善用工具。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1013431

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX