python - PIL - 需要抖动,但限制调色板会导致问题

标签 python image python-imaging-library dithering

我是 Python 新手,正在尝试使用 PIL 执行 Arduino 项目所需的解析任务。这个问题与 Image.convert() 方法以及调色板、抖动等选项有关。

我有一些硬件一次只能显示 16 种颜色的图像(但它们可以指定为 RGB 三元组)。因此,我想自动执行以下任务:拍摄任意真彩色 PNG 图像,选择“最佳”16 色调色板来表示它,并将图像转换为仅包含 16 种颜色的调色板。

我想使用抖动。问题是,image.convert() 方法似乎有点古怪。它的参数没有完整记录 ( PIL documentation for Image.convert() ),所以我不知道这是我的错还是该方法有问题。

我的代码的一个简单版本如下:

import Image
MyImageTrueColor = Image.new('RGB',100,100) # or whatever dimension...

# I paste some images from several other PNG files in using MyImageTrueColor.paste()

MyImageDithered = MyImageTrueColor.convert(mode='P',
    colors=16,
    dither=1
    )

根据我所做的一些搜索(例如:How to reduce color palette with PIL),我认为这种方法应该可以满足我的要求,但运气不好。它会使图像抖动,但会产生超过 16 种颜色的图像。

为了确定,我删除了“dither”参数。相同的输出。

我重新添加了“dither=1”参数并加入了 Image.ADAPTIVE 参数(如上面的链接所示)只是为了看看发生了什么。这导致图像包含 16 种颜色,但没有抖动。

我是不是漏掉了什么? PIL 有问题吗?我想出的解决方案是执行 2 个步骤,但这似乎草率且不必要。我想弄清楚如何正确地做到这一点 :-) 为了完整起见,这里是我的代码版本,它产生了正确的结果——但它以一种草率的方式做到了。 (第一步生成超过 16 种颜色的抖动图像,第二步生成仅包含 16 种颜色的图像。)

MyImage_intermediate = MyImageTrueColor.convert(mode='P',
    colors=16
    )
MyImageDithered = MyImage_intermediate.convert(mode='P',
    colors=16,
    dither=1,
    palette=Image.ADAPTIVE
    )

谢谢!

最佳答案

好吧,你没有正确调用,所以它不应该工作......但即使我们调用正确,我也不确定它是否有效。

首先,PIL 手册的“官方”免费版本既不完整又过时;草稿版本在 http://effbot.org/imagingbook/image.htm不太完整和过时。

im.convert(“P”, **options) ⇒ image

Same, but provides better control when converting an “RGB” image to an 8-bit palette image. Available options are:

dither=. Controls dithering. The default is FLOYDSTEINBERG, which distributes errors to neighboring pixels. To disable dithering, use NONE.

palette=. Controls palette generation. The default is WEB, which is the standard 216-color “web palette”. To use an optimized palette, use ADAPTIVE.

colors=. Controls the number of colors used for the palette when palette is ADAPTIVE. Defaults to the maximum value, 256 colors.

所以,首先,如果没有ADAPTIVE,您就不能使用colors——原因很明显:唯一的选择是WEB,它只处理固定的 216 色调色板。

其次,您不能将 1 传递给 dither。如果它恰好是 FLOYDSTEINBERG 的值,那可能会起作用,但那是 3。因此,您正在传递一个未记录的值;谁知道那会做什么?特别是因为,查看所有听起来像是抖动算法可能名称的常量,没有一个值是 1。

因此,您可以尝试将其更改为 dither=Image.FLOYDSTEINBERG(连同 palette=Image.ADAPTIVE),看看是否会有所不同。

但是,看看代码,看起来这不会有任何好处:

if mode == "P" and palette == ADAPTIVE:
    im = self.im.quantize(colors)
    return self._new(im)

这发生在我们到达抖动代码之前。所以它与调用(现已弃用/私有(private))方法 quantize 完全相同。

多个线程表明高级 convert 函数仅用于公开“抖动到 web 调色板”或“映射到最近的 N 种颜色”。这似乎在 1.1.6 及更高版本中略有变化,但文档和实现仍然不完整。在 http://comments.gmane.org/gmane.comp.python.image/2947其中一位开发人员建议阅读 PIL/Image.py 源代码。

看来这就是您需要做的。无论 Image.convertImage.WEB 模式下做什么,您都想这样做——但是要使用由 Image.quantize(colors)< 生成的调色板,而不是 Web 调色板。

当然,大部分内容都发生在 C 代码中(在 self.im.quantizeself.im.convert 等下),但是您也许可以做类似这样的伪代码:

dummy = img.convert(mode='P', paletter='ADAPTIVE', colors=16)
intermediate = img.copy()
intermediate.setpalette(dummy.palette)
dithered = intermediate._new(intermediate.im.convert('P', Image.FLOYDSTEINBERG))

话又说回来,你可能不会。您可能需要查看 C header 甚至源代码才能找到答案。或者在 PIL 邮件列表上提问。

PS,如果您不熟悉 PIL 的内部结构,img.im 是 PIL Image 对象 img 下的 C 成像对象。根据我过去的经验,前 3 次浏览 PIL 代码时并不清楚这一点,然后突然间一切都变得更有意义了。

关于python - PIL - 需要抖动,但限制调色板会导致问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12645492/

相关文章:

javascript - 图像作为按钮

python - 使用 python/PIL 自动裁剪图像

python - 在 Kivy Canvas 上显示 PIL 图片

python - 如何将参数传递给 tkinter 中的事件处理程序?

python - 在 Django 中删除对象后将数据保存在变量中

python - 何时转换 GPS 坐标

使用经典 ASP 上传图片

python - 是否可以根据其他可选参数将 argparse 的可选参数设置为默认值?

java - 为什么我的图像不能显示在我的 Java Applet 中?

python - python 的 PIL 和 ImageMagick 绑定(bind)有什么区别?