使用PIL中的Image.point()方法操作像素数据

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (7517)

我正在使用Python成像库若要用定义颜色关系的查找表对黑白图像进行着色,请执行以下操作。查找表只是RGB元组的256个元素列表:

>>> len(colors)
256
>>> colors[0]
(255, 237, 237)
>>> colors[127]
(50, 196, 33)
>>> 

我的第一个版本使用了getpixel()putpixel()方法:

    for x in range(w):
        for y in range(h):
            pix = img.getpixel((x,y))
            img.putpixel((x,y), colors[pix[0]])

这太慢了。profile报告指出putpixelgetpixel方法作为罪魁祸首。做个小调查(比如,看医生),我就会发现“请注意,此方法相对较慢。“关于:putpixel...(实际运行时*53岁putpixel和50年代getpixel1024x1024图像)

根据文档中的建议,我im.load()并直接访问像素:

    pixels = img.load()
    for x in range(w):
        for y in range(h):
            pix = pixels[x, y]
            pixels[x, y] = colors[pix[0]]                

处理速度加快了一个数量级,但仍在继续缓慢:大约3.5s来处理1024x1024图像。

对PIL文档的深入研究似乎表明Image.point()一点儿没错为此目的:

im.point(table)=>图像im.point(function)=>图像 返回图像的副本,其中每个像素都通过给定的表进行映射。该表应包含图像中每个波段的256个值。如果使用函数,则应该使用单个参数。对每个可能的像素值调用一次该函数,并将结果表应用于图像的所有波段。

PIL的文档很简陋,而且我没有太多的图像处理经验。我搜索了一下,找到了几个例子,但是没有任何东西让我的用法“点击”。因此,最后,我的问题是:

  • Image.point()适合这份工作的工具?
  • 什么格式/结构Image.point()期待这张桌子?
  • 有人能粗略地写出一个示例实现吗?到目前为止,我尝试过的每一次迭代都得到了一个直接的黑色图像。
提问于
用户回答回答于

Image.point()是这个作业的合适工具吗?

Image.point()很适合这份工作

Image.point()期望表的格式/结构是什么?

你应该把清单压平,而不是[(12, 140, 10), (10, 100, 200), ...]用途:

[12, 140, 10, 10, 100, 200, ...]

下面是我刚刚尝试过的一个简单的例子:

im = im.point(range(256, 0, -1) * 3)

需要更多的颜色控制,并且你觉得Image.point不适合你,你也可以使用Image.getdataImage.putdata比两者都更快地改变颜色loadputpixel...。它比Image.point尽管如此。

Image.getdata给出所有像素的列表,修改它们,然后使用Image.putdata。就这么简单。但是试着用Image.point首先。

编辑

我在第一个解释中犯了一个错误,现在我要正确地解释:

颜色表实际上是这样的

[0, 1, 2, 3, 4, 5, ...255, 0, 1, 2, 3, ....255, 0, 1, 2, 3, ...255]

每个乐队的范围相邻。要将颜色(0,0,0)更改为(10,100,10),需要如下所示:

[10, 1, 2, 3, 4, 5, ...255, 100, 1, 2, 3, ....255, 10, 1, 2, 3, ...255]

若要将颜色列表转换为正确的格式,请尝试如下:

table = sum(zip(*colors), ())
用户回答回答于

我觉得这可能更典型point

# split the image into individual bands
source = im.split()

R, G, B = 0, 1, 2

# select regions where red is less than 100
mask = source[R].point(lambda i: i < 100 and 255)

# process the green band
out = source[G].point(lambda i: i * 0.7)

# paste the processed band back, but only where red was < 100
source[G].paste(out, None, mask)

# build a new multiband image
im = Image.merge(im.mode, source)

扫码关注云+社区