46

伙计们,我正在寻求一些帮助。我是一名新手程序员,我目前遇到的一个问题是尝试将黑白.jpg图像转换为列表,然后我可以将其调制为音频信号。这是创建 python SSTV 程序的大型项目的一部分。

我已经导入了 PIL 模块并试图调用内置函数:list(im.getdata()). 当我调用它时,python 崩溃了。是否有某种方法可以将图像(始终为 320x240)分解为 240 行以使计算更容易?或者我只是调用了错误的函数。

如果有人有任何建议,请开火。如果有人有使用 python 生成调制音频的经验,我很乐意接受他们愿意传授的任何“智慧之珠”。提前致谢

4

9 回答 9

71

当您调用 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)]
于 2009-07-10T14:04:23.830 回答
41

如果您安装了numpy,您可以尝试:

data = numpy.asarray(im)

(我在这里说“尝试”,因为不清楚为什么getdata()不适合你,我不知道是否asarray使用 getdata,但值得一试。)

于 2009-07-10T15:12:52.913 回答
16

我假设你得到一个错误,比如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)
于 2009-07-10T20:55:24.303 回答
3

不是 PIL,但scipy.misc.imread可能仍然很有趣:

import scipy.misc
im = scipy.misc.imread('um_000000.png', flatten=False, mode='RGB')
print(im.shape)

(480, 640, 3)

所以它是(高度,宽度,通道)。所以你可以通过

for y in range(im.shape[0]):
    for x in range(im.shape[1]):
        color = tuple(im[y][x])
        r, g, b = color
于 2016-07-24T08:56:36.787 回答
2

或者,如果您想计算白色或黑色像素

这也是一个解决方案:

from PIL import Image
import operator

img = Image.open("your_file.png").convert('1')
black, white = img.getcolors()

print black[0]
print white[0]
于 2013-11-16T12:31:29.180 回答
2
data = numpy.asarray(im)

注意:在 PIL 中,img 是 RGBA。在 cv2 中,img 是 BGRA。

我强大的解决方案:

def cv_from_pil_img(pil_img):
    assert pil_img.mode=="RGBA"
    return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGBA2BGRA)
于 2017-06-13T08:15:54.777 回答
2
pixVals = list(pilImg.getdata())

输出是图片中所有 RGB 值的列表:

[(248, 246, 247), (246, 248, 247), (244, 248, 247), (244, 248, 247), (246, 248, 247), (248, 246, 247), (250, 246, 247), (251, 245, 247), (253, 244, 247), (254, 243, 247)]
于 2019-08-21T08:46:16.210 回答
1

正如我上面评论的,问题似乎是从 PIL 内部列表格式到标准 python 列表类型的转换。我发现 Image.tostring() 更快,根据您的需要,它可能就足够了。在我的例子中,我需要计算图像数据的 CRC32 摘要,它非常适合。

如果您需要执行更复杂的计算,则可能需要涉及 numpy 的 tom10 响应。

于 2014-03-19T10:49:16.677 回答
1

看起来 PILlow 可能已更改tostring()tobytes(). 当尝试提取 RGBA 像素以将它们放入 OpenGL 纹理中时,以下内容对我有用(在glTexImage2D我为简洁起见省略的调用中)。

from PIL import Image
img = Image.open("mandrill.png").rotate(180).transpose(Image.FLIP_LEFT_RIGHT)

# use img.convert("RGBA").tobytes() as texels
于 2017-03-15T15:19:47.197 回答