PIL-希望抖动,但限制调色板会导致问题 [英] PIL - Dithering desired, but restricting color palette causes problems

查看:160
本文介绍了PIL-希望抖动,但限制调色板会导致问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我拥有一些能够一次仅显示16种颜色的图像的硬件(但可以将其指定为RGB三联体).因此,我想自动执行以下任务:拍摄任意真彩色PNG图像,选择一个最佳" 16色调色板来表示它,然后将图像转换为仅包含16色的调色板化图像.

我想使用抖动.问题是image.convert()方法似乎有点时髦.尚未完整记录其参数( Image.convert的PIL文档()),所以我不知道这是我的错还是该方法有问题.

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

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
    )

根据我进行的一些搜索(例如:如何使用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
    )

谢谢!

解决方案

好吧,您调用的东西不正确,所以它不应该工作……但是即使我们调用的东西正确,我也不确定会起作用.

首先,PIL手册的官方"免费版本既不完整,也已过时; http://effbot.org/imagingbook/image.htm 的草稿版本不太完整,而且过时了.

im.convert("P",** options)⇒图片

相同,但是在将"RGB"图像转换为 8位调色板图像.可用的选项是:

dither =.控制抖动.默认值为FLOYDSTEINBERG,其中 将误差分布到相邻像素.要禁用抖动,请使用 没有.

palette =.控制调色板的生成.默认值为WEB,即 标准的216色网络调色板".要使用优化的调色板,请使用 自适应.

colors =.在以下情况下控制调色板使用的颜色数量 调色板是自适应的.默认为最大值,即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)

这是在我们获得抖动代码之前发生的.因此,这与调用(现在不建议使用/私有的)量化方法完全相同.

多个线程表明,高级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图像对象img下面的C成像对象.从我过去的经验来看,前3次浏览PIL代码尚不清楚,然后突然之间所有事情变得更有意义了.

I am new to Python, and trying to use PIL to perform a parsing task I need for an Arduino project. This question pertains to the Image.convert() method and the options for color palettes, dithering etc.

I've got some hardware capable of displaying images with only 16 colors at a time (but they can be specified RGB triplets). So, I'd like to automate the task of taking an arbitrary true-color PNG image, choosing an "optimum" 16-color palette to represent it, and converting the image to a palettized one containing ONLY 16 colors.

I want to use dithering. The problem is, the image.convert() method seems to be acting a bit funky. Its arguments aren't completely documented (PIL documentation for Image.convert()) so I don't know if it's my fault or if the method is buggy.

A simple version of my code follows:

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
    )

Based on some searches I did (e.g.: How to reduce color palette with PIL) I would think this method should do what I want, but no luck. It dithers the image, but yields an image with more than 16 colors.

Just to make sure, I removed the "dither" argument. Same output.

I re-added the "dither=1" argument and threw in the Image.ADAPTIVE argument (as shown in the link above) just to see what happened. This resulted in an image that contained 16 colors, but NO dithering.

Am I missing something here? Is PIL buggy? The solution I came up with was to perform 2 steps, but that seems sloppy and unnecessary. I want to figure out how to do this right :-) For completeness, here's the version of my code that yields the correct result - but it does it in a sloppy way. (The first step results in a dithered image with >16 colors, and the second results in an image containing only 16 colors.)

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

Thanks!

解决方案

Well, you're not calling things properly, so it shouldn't be working… but even if we were calling things right, I'm not sure it would work.

First, the "official" free version of the PIL Handbook is both incomplete and out of date; the draft version at http://effbot.org/imagingbook/image.htm is less incomplete and out of date.

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.

So, first, you can't use colors without ADAPTIVE—for obvious reason: the only other choice is WEB, which only handles a fixed 216-color palette.

And second, you can't pass 1 to dither. That might work if it happened to be the value of FLOYDSTEINBERG, but that's 3. So, you're passing an undocumented value; who knows what that will do? Especially since, looking through all of the constants that sound like possible names for dithering algorithms, none of them have the value 1.

So, you could try changing it to dither=Image.FLOYDSTEINBERG (along with palette=Image.ADAPTIVE) and see if that makes a difference.

But, looking at the code, it looks like this isn't going to do any good:

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

This happens before we get to the dithering code. So it's exactly the same as calling the (now deprecated/private) method quantize.

Multiple threads suggest that the high-level convert function was only intended to expose "dither to web palette" or "map to nearest N colors". That seems to have changed slightly with 1.1.6 and beyond, but the documentation and implementation are both still incomplete. At http://comments.gmane.org/gmane.comp.python.image/2947 one of the devs recommends reading the PIL/Image.py source.

So, it looks like that's what you need to do. Whatever Image.convert does in Image.WEB mode, you want to do that—but with the palette that would be generated by Image.quantize(colors), not the web palette.

Of course most of the guts of that happens in the C code (under self.im.quantize, self.im.convert, etc.), but you may be able to do something like this pseudocode:

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

Then again, you may not. You may need to look at the C headers or even source to find out. Or maybe ask on the PIL mailing list.

PS, if you're not familiar with PIL's guts, img.im is the C imaging object underneath the PIL Image object img. From my past experience, this isn't clear the first 3 times you skim through PIL code, and then suddenly everything makes a lot more sense.

这篇关于PIL-希望抖动,但限制调色板会导致问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆