python - numpy.ndarray,其形状(高度、宽度、n)来自每个图像像素的 n 个值

标签 python python-3.x numpy python-imaging-library

我的输入是模式为RGBRGBAPIL.Image.Image,我需要填充一个numpy。 ndarray 具有根据每个像素的 RGB 值计算的 3 个浮点值。输出数组应该可以通过像素坐标进行索引。我找到了以下方法来做到这一点:

import numpy as np
from PIL import Image

def generate_ycbcr(img: Image.Image):
    for r, g, b in img.getdata():
        yield 0.299 * r + 0.587 * g + 0.114 * b
        yield 128 - 0.168736 * r - 0.331264 * g + 0.5 * b
        yield 128 + 0.5 * r - 0.418688 * g - 0.081312 * b

def get_ycbcr_arr(img: Image.Image):
    width, height = img.size
    arr = np.fromiter(generate_ycbcr(img), float, height * width * 3)
    return arr.reshape(height, width, 3)

它有效,但我怀疑有更好和/或更快的方法。有的话请告诉我,没有的话也请告诉我。

注意:我知道我可以将图像 convert() 转换为 YCbCr,然后从中填充 numpy.array,但是转换四舍五入为整数值,这不是我需要的。

最佳答案

对于初学者,您可以将图像直接转换为 numpy 数组,并使用矢量化操作来执行您想要的操作:

def get_ycbcr_vectorized(img: Image.Image):
    R,G,B = np.array(img).transpose(2,0,1)[:3] # ignore alpha if present
    Y = 0.299 * R + 0.587 * G + 0.114 * B
    Cb = 128 - 0.168736 * R - 0.331264 * G + 0.5 * B
    Cr = 128 + 0.5 * R - 0.418688 * G - 0.081312 * B
    return np.array([Y,Cb,Cr]).transpose(1,2,0)

print(np.array_equal(get_ycbcr_arr(img), get_ycbcr_vectorized(img))) # True

但是,您确定直接转换为 'YCbCr' 会有那么大的不同吗?我测试了上面函数中定义的转换:

import matplotlib.pyplot as plt
def aux():
    # generate every integer R/G/B combination
    R,G,B = np.ogrid[:256,:256,:256]
    Y = 0.299 * R + 0.587 * G + 0.114 * B
    Cb = 128 - 0.168736 * R - 0.331264 * G + 0.5 * B
    Cr = 128 + 0.5 * R - 0.418688 * G - 0.081312 * B

    # plot the maximum error along one of the RGB channels
    for arr,label in zip([Y,Cb,Cr], ['Y', 'Cb', 'Cr']):
        plt.figure()
        plt.imshow((arr - arr.round()).max(-1))
        plt.xlabel('R')
        plt.ylabel('G')
        plt.title(f'max_B ({label} - {label}.round())')
        plt.colorbar()

aux()   
plt.show()

结果表明,最大绝对误差为 0.5,尽管这些误差发生在所有像素上:

RGB -> Y error RGB -> Cb error RGB -> Cr error

所以,是的,这可能是一个较大的相对错误,但这不一定是一个大问题。

如果内置转换足够:

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

这就是您所需要的。

关于python - numpy.ndarray,其形状(高度、宽度、n)来自每个图像像素的 n 个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53027266/

相关文章:

python - 一次调用方法以在 Django Rest Framework 序列化程序中设置多个字段

python - 将 numpy/scipy 链接到串行 ATLAS

python - 如何在整个类中声明全局变量?

python - 是否可以访问 pandas 中给定的列名列表的数据?

python - 在 Sendgrid 列表中添加更多联系人

python - 崩溃可能是因为 pygame

Python,如何制作异步数据生成器?

python numpy 成对编辑距离

python - 提取 numpy 数组中每个元素的最后两位数字的有效方法

python-3.x - 使用 USB IP 服务器时 OpenCV 返回所有黑帧