【问题标题】:PIL - Dithering desired, but restricting color palette causes problemsPIL - 需要抖动,但限制调色板会导致问题
【发布时间】:2012-09-20 15:53:37
【问题描述】:

我是 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=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
    )

谢谢!

【问题讨论】:

  • 上面显示的链接明确表示“我正在使用 Image.ADAPTIVE 来避免抖动”,所以我不确定你是否对使用 Image.ADAPTIVE 避免抖动感到惊讶……
  • 顺便说一下,我怀疑抖动到 216 种网络颜色,然后量化到网络调色板的最佳 16 种颜色,通常会给您带来比仅量化到最适合您的 16 种颜色更糟糕的结果原始图像。您的测试是否显示其他结果?如果是这样,也许您的解决方法是可以接受的。

标签: python image python-imaging-library dithering


【解决方案1】:

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

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

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

相同,但在将“RGB”图像转换为 8 位调色板图像。可用选项有:

抖动=。控制抖动。默认值为 FLOYDSTEINBERG,即 将误差分布到相邻像素。要禁用抖动,请使用 无。

调色板=。控制调色板生成。默认是WEB,即 标准的 216 色“网络调色板”。要使用优化的调色板,请使用 自适应。

颜色=。控制调色板使用的颜色数量 调色板是自适应的。默认为最大值,256色。

因此,首先,您不能在没有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)

这发生在我们得到抖动代码之前。所以它与调用(现已弃用/私有)方法 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 头文件甚至源代码才能找到答案。或者在 PIL 邮件列表中询问。

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

【讨论】:

  • 有没有办法将图像映射到任意调色板?如果是这样,您可以分两遍进行,首先生成调色板,然后使用抖动重新映射。
  • @MarkRansom:问题是 image.convert 只抖动到 web 调色板,所以只能完成量化到 16 种颜色,然后抖动到 216,这与他想要的相反。但我认为底层的C库可以做到这一点,这就是最后的伪代码。
猜你喜欢
  • 2015-06-08
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 1970-01-01
  • 2016-09-15
  • 1970-01-01
  • 2015-05-07
  • 1970-01-01
相关资源
最近更新 更多