【问题标题】:PIL adding text to a gif frames adds noise to the picturePIL 将文本添加到 gif 帧会为图片添加噪点
【发布时间】:2021-03-06 08:39:10
【问题描述】:

我正在使用 PIL 创建一个简单的 GIF 动画:

from PIL import Image, ImageDraw, ImageFont

images = []

for x, i in enumerate(range(10)):
    image = Image.new(mode="RGB", size=(320, 60), color="orange")

    draw = ImageDraw.Draw(image)
    fnt = ImageFont.truetype('font.ttf', size=10)
    draw.text((10, 10), ("%s" % x), fill=(0, 0, 255), font=fnt)
    images.append(image)

images[0].save("result/pil.gif", save_all=True, append_images=images[1:], duration=1000, loop=0, format="GIF")

问题是每当我使用 Draw.text 时,图像的背景都会出现某种白色的鼻子:

我发现了一些信息,我必须从第一帧使用 getpalette 并为所有其他帧使用 putpalette,如下所示:

for x, i in enumerate(range(10)):
    image = Image.new(mode="RGB", size=(320, 60), color="orange")

    if x == 0:
        palette = image.getpalette()
    else:
        image.putpalette(palette)

但它只给了我:ValueError: illegal image mode

背景嘈杂的原因是什么,我该如何解决?

UPD 我可以通过将图像模式更改为“P”来修复背景,但在这种情况下,我的字体变得不可读。这些是 RGB 模式(字体很好)和 P 模式(字体很糟糕)的示例:

为什么我会得到漂亮的背景或漂亮的字体,但不能两者兼得?有解决办法吗?

【问题讨论】:

  • 如果可以选择,请考虑使用 .apng 或 .webp 格式

标签: python python-imaging-library gif animated-gif


【解决方案1】:

这是dithering 发生的情况,因为 gif 只能包含大小为 256 的 palette 中的颜色。PIL 很可能使用非常基本的算法将 RGB 格式转换为 gif 所需的索引格式。由于您的图像包含颜色#ff9900#ffcc00,因此调色板可能由每个字节的十六进制值00, 33, 66, 99, cc, ff 组成,大小为6x6x6 = 216,非常适合256 个可能的值。 'orange' 的值为#ffa500,不能用这样的调色板表示,所以背景用最接近的可用颜色填充。

您可以尝试使用颜色'#ff9900' 而不是'orange'。希望这种颜色可以通过调色板来表示,因为它存在于您的嘈杂图像中。

您还可以尝试使用您自己的调色板作为quantize 方法中的参数,按照this answer 中的建议,将RGB 转换为索引格式。添加以下行会导致nice solid background

image = image.quantize(method=Image.MEDIANCUT)

或者你可以只用 PNG 格式保存 RGB 图像。在这种情况下,它将被保存为 APNG 图像。

images[0].save("pil.png", save_all=True, append_images=images[0:],duration=1000, loop=0, format="PNG")

【讨论】:

  • image = image.quantize(method=Image.MEDIANCUT) - 这非常适合我!它略微增加了执行时间,但仍然可以接受。我的 gif 中永远不会有太多颜色,但它们总是不可预测的(用户输入的数据)。这就是为什么量化对我来说是最好的选择。谢谢!
【解决方案2】:

user13044086 给出了该问题的通用版本,具体是 gif 是一种托盘格式,要将原始 RGB 转换为调色板枕头需要将其从“真彩色”限制为仅 256 种颜色。

为此,它会将convert 图像转换为模式 L,并且您可以在文档中看到,如果没有给出转换矩阵,这只是使用默认参数调用 quantize 的别名。这里的相关默认参数是dither,这意味着如果图像有超过 256 种颜色,则尝试通过附近颜色的单个点来“模拟”缺失的颜色。

现在您可能会抱怨您没有超过 256 种颜色,但您可能会这样做是因为字体抗锯齿,而且算法不一定有“味道”,所以不是在字母中抖动,而是在字母中非常明显地抖动背景。

您可以通过显式量化提供建议的显式方法来缓解此问题,或者只是禁用抖动(这可能会产生较低质量的结果,但肯定会更快):

images.append(image.quantize(dither=Image.NONE))

手动制作您自己的调色板并将其传递给 quantize 也可以。

【讨论】:

    猜你喜欢
    • 2012-07-08
    • 1970-01-01
    • 2011-07-16
    • 2013-11-19
    • 1970-01-01
    • 2011-10-23
    • 2021-10-04
    • 2021-02-08
    • 2021-12-23
    相关资源
    最近更新 更多