在PIL中使用Image.point()方法来处理像素数据
image
image-manipulation
image-processing
python
6
0

我正在使用Python Imaging Library将带有定义颜色关系的查找表的黑白图像着色。查找表只是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方法的罪魁祸首。稍作调查(即阅读文档),我发现“ 请注意,此方法相对较慢。 ” re: putpixel 。 ( 实际运行时间 :在53秒putpixel和50年代getpixel用于1024×1024图像)

根据文档中的建议,我改用了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]]                

处理速度加快了一个数量级,但仍然很慢:处理1024x1024图像大约需要3.5秒。

对PIL文档的更彻底的研究似乎表明Image.point() 正是用于此目的:

im.point(table) =>图片

im.point(function) =>图片

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

我花了一些时间在界面上乱搞,但似乎不太正确。原谅我的无知,但是PIL的文档简直就是草率,我没有太多图像处理经验。我已经在Google上搜索了一些示例,但是没有什么使我感到“点击”。因此,最后,我的问题是:

  • Image.point()是适合此工作的工具吗?
  • Image.point()应该使用哪种格式/结构的表?
  • 有人可以粗略举例实现吗?到目前为止,我尝试过的每个迭代都以纯黑色图像结束。
参考资料:
Stack Overflow
收藏
评论
共 2 个回答
高赞 时间 活跃

我认为像这样逐个频带地point可能会更典型(直接从PIL 教程中获得 ):

# 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)
收藏
评论

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), ())

我认为我的第一个例子应该为您展示好运。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号