You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用NumPy直接将图像导入为RGB三元组构成的2D数组?

有没有NumPy函数/方法可直接将图像导入为RGB三元组组成的2D数组?

我想知道是否存在NumPy函数或方法,能直接把图像导入成由RGB三元组组成的2D数组,而不是常规的数值3D数组。

目前我用的解法是:

from PIL import Image
import numpy as np

dt = np.dtype([('R','u1'), ('G','u1'), ('B','u1')])

img_in_2D_array = np.asarray(img, dtype='u1').view(dtype=dt).squeeze()

但我想找更简便的方式,比如通过某个函数/方法的参数直接实现,望指教。

我希望把图像表示成三元组的2D数组,是为了方便操作RGB值,比如将彩色图像转为黑白(我知道用np.average()能实现,但更复杂的操作可能不好直接完成)。

示例运行结果:

img_in_2D_array.shape  # 返回 (375, 500)
img_in_2D_array[0,0]  # 返回 (58, 76, 28)

显示图像的代码:

Image.fromarray(img_in_2D_array.astype(dt), 'RGB')

注:我试过对3D图像数组用np.apply_along_axis(),但速度明显比2D数组的方式慢。


研究更新

我意识到上面的img_in_2D_array并不是新数组,只是现有3D数组的视图。这个视图表现得像三元组数组,但内存里还是原始的3D数组,不用担心内存问题。

以下是这个“2D数组”的基本属性示例:

from PIL import Image
import numpy as np

arr3D = np.asarray(img, dtype=np.uint8)

dt = np.dtype([('R', 'u1'), ('G', 'u1'), ('B', 'u1')])

arr2D = arr3D.view(dtype=dt).squeeze()

arr2D.base is arr3D  # 返回True,说明是视图
arr2D[0,0]  # 返回 (58, 76, 28),看起来像元组
type(arr2D[0,0]) # 返回numpy.void,不是物理元组
arr2D.shape  # 返回 (375, 500),表现为2D数组
arr2D.ndim  # 返回2
arr2D.nbytes  # 返回562500,和arr3D.nbytes相等

这种方式能方便高效地应用向量化函数:

@np.vectorize
def Y(args):
    R, G, B = args
    return 0.299 * R + 0.587 * G + 0.114 * B

grey = Y(arr2D)

Image.fromarray(grey.astype('u1'), 'L')

除了np.apply_along_axis,我不知道怎么直接对arr3D应用函数Y,但正如Cris指出的,这个方法只是隐藏了循环,速度很慢。用普通版Y测试:

def Y(args):
    R, G, B = args
    return 0.299 * R + 0.587 * G + 0.114 * B

grey = np.apply_along_axis(Y, 2, arr3D)

Image.fromarray(grey.astype('u1'), 'L')

功能一样,但速度慢4倍左右。

我觉得用2D视图的优势是能轻松给RGB分量应用任意函数Y,不过可能我忽略了更直接的方法,毕竟我还在学习阶段。


彩色转灰度方法速度测试

在Cris的建议下,我对比了所有能想到的彩色图像转灰度的方法,以下是重复100次的测试结果(图像尺寸(375, 500),uint8类型,旧款Intel i5处理器,Win10系统):

方法1:0.40 - 0.50 秒

grey = arr3D @ [0.299, 0.587, 0.114]

方法2:0.50 - 0.70 秒

grey = arr3D[:,:,0]*0.299 + arr3D[:,:,1]*0.587 + arr3D[:,:,2]*0.114

方法3:0.95 - 1.05 秒

grey = (arr3D * [0.299, 0.587, 0.114]).sum(axis=2)

方法4:1.0 - 1.10 秒

grey = np.average(image, weights=[0.299, 0.587, 0.114], axis=2)

方法5:14 - 15 秒

grey = Y(arr2D)  # 参见上述定义的Y和arr2D

方法6:~300 秒

grey = np.apply_along_axis(Y, 2, arr3D)  # 参见上述定义的Y

测试结果验证了Cris的建议:如果看重速度,要避免用@np.vectorize,更别说np.apply_along_axis了。有意思的是,np.average和.sum的速度只有矩阵乘积或直接数组运算的一半。


循环解法(供参考)

方法7:~225 秒

grey = loopY(arr3D)

其中loopY定义:

def loopY(image):
    res = np.empty(image.shape[:-1])
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            res[i, j] = Y(image[i, j])

    return res

可以看到,np.apply_along_axis是最慢的方案,甚至比手动循环还慢。


内容的提问来源于stack exchange,提问作者isCzech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 00:02:24