PIL将文本添加到gif帧会给图片添加噪音

2024-04-26 11:19:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用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时,图像的背景都会出现某种白色noze:

enter image description here

我发现一些信息,我必须使用第一帧的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模式(字体很糟糕)的示例:

enter image description hereenter image description here

为什么我要么有好的背景,要么有好的字体,但不是两者都有?有解决办法吗


Tags: inimageforsizepilmode模式字体
2条回答

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

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

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

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

enter image description here

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

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

enter image description here

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

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

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

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

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

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

相关问题 更多 >