从PIL获取像素值列表

55 投票
9 回答
204140 浏览
提问于 2025-04-15 12:48

我正在尝试把一张黑白的 .jpg 图片转换成一个列表,然后再把这个列表变成音频信号。

我已经导入了PIL模块,并且想要使用一个内置的函数:list(im.getdata())。但是当我调用这个函数时,Python就崩溃了。有没有什么方法可以把这张图片(总是320x240的大小)分成240行,这样计算起来会更简单一些?还是说我调用的函数不对?

9 个回答

21

我猜你遇到的错误是这样的:TypeError: 'PixelAccess' object is not iterable...对吧?

你可以查看这个Image.load的文档,了解如何访问图片的像素。

简单来说,想要获取一张图片中的所有像素,使用PIL库可以这样做:

from PIL import Image
i = Image.open("myfile.png")

pixels = i.load() # this is not a list, nor is it list()'able
width, height = i.size

all_pixels = []
for x in range(width):
    for y in range(height):
        cpixel = pixels[x, y]
        all_pixels.append(cpixel)

这段代码会把每个像素都添加到all_pixels中。如果这个文件是RGB格式的图片(即使它实际上只是黑白图像),这些像素会以元组的形式出现,比如:

(255, 255, 255)

如果你想把图片转换成单色,只需对这三个值求平均值——所以,最后三行代码可以改成:

cpixel = pixels[x, y]
bw_value = int(round(sum(cpixel) / float(len(cpixel))))
# the above could probably be bw_value = sum(cpixel)/len(cpixel)
all_pixels.append(bw_value)

或者你可以计算亮度(加权平均):

cpixel = pixels[x, y]
luma = (0.3 * cpixel[0]) + (0.59 * cpixel[1]) + (0.11 * cpixel[2])
all_pixels.append(luma)

或者得到纯粹的1位黑白效果:

cpixel = pixels[x, y]
if round(sum(cpixel)) / float(len(cpixel)) > 127:
    all_pixels.append(255)
else:
    all_pixels.append(0)

在PIL中可能还有其他方法可以更快地进行RGB -> BW的转换,但这个方法也能用,而且速度并不算慢。

如果你只想对每一行进行计算,可以跳过把所有像素添加到中间列表的步骤。例如,计算每一行的平均值可以这样做:

from PIL import Image
i = Image.open("myfile.png")

pixels = i.load() # this is not a list
width, height = i.size
row_averages = []
for y in range(height):
    cur_row_ttl = 0
    for x in range(width):
        cur_pixel = pixels[x, y]
        cur_pixel_mono = sum(cur_pixel) / len(cur_pixel)
        cur_row_ttl += cur_pixel_mono
    
    cur_row_avg = cur_row_ttl / width
    row_averages.append(cur_row_avg)

print "Brighest row:",
print max(row_averages)
46

如果你安装了numpy,你可以试试下面的代码:

data = numpy.asarray(im)

(我在这里说“试试”,因为不太清楚为什么getdata()对你不起作用,我也不知道asarray是否使用了getdata,不过试一下是值得的。)

78

当你调用 getdata() 时,Python 不应该崩溃。可能是你用的图片坏掉了,或者你的 PIL 安装有问题。你可以试试用另一张图片,或者把你正在使用的那张图片发上来。

下面的代码应该可以按照你想要的方式处理图片:

from PIL import Image
im = Image.open('um_000000.png')

pixels = list(im.getdata())
width, height = im.size
pixels = [pixels[i * width:(i + 1) * width] for i in xrange(height)]

撰写回答