使用PIL将图像转换为特定调色板而不抖动 [英] Convert image to specific palette using PIL without dithering

查看:224
本文介绍了使用PIL将图像转换为特定调色板而不抖动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Pillow库(Python Image Library,PIL)将PNG格式的RGB图像转换为使用特定的索引调色板。但是我希望使用圆形到最接近的颜色方法进行转换,而不是抖动,因为图像是像素艺术,抖动会扭曲区域的轮廓并向想要平坦的区域添加噪声。

I am trying to convert an RGB image in PNG format to use a specific indexed palette using the Pillow library (Python Image Library, PIL). But I want to convert using the "round to closest color" method, not dithering, because the image is pixel art and dithering would distort the outlines of areas and add noise to areas that are intended to be flat.

我试过 Image.Image.paste(),它使用了四种指定的颜色,但它产生了一个抖动的图像:

I tried Image.Image.paste(), and it used the four specified colors, but it produced a dithered image:

from PIL import Image
oldimage = Image.open("oldimage.png")
palettedata = [0, 0, 0, 102, 102, 102, 176, 176, 176, 255, 255, 255]
newimage = Image.new('P', oldimage.size)
newimage.putpalette(palettedata * 64)
newimage.paste(oldimage, (0, 0) + oldimage.size)
newimage.show()    

我尝试 Image.Image.quantize(),如 pictu对类似问题的回答,但它也产生了抖动:

I tried Image.Image.quantize() as mentioned in pictu's answer to a similar question, but it also produced dithering:

from PIL import Image
palettedata = [0, 0, 0, 102, 102, 102, 176, 176, 176, 255, 255, 255]
palimage = Image.new('P', (16, 16))
palimage.putpalette(palettedata * 64)
oldimage = Image.open("School_scrollable1.png")
newimage = oldimage.quantize(palette=palimage)
newimage.show()

我试过 Image.Image.convert(),它转换图像时没有抖动,但它包含了除了那些指定的,可能是因为它使用了网页调色板或自适应调色板

I tried Image.Image.convert(), and it converted the image without dithering, but it included colors other than those specified, presumably because it used either a web palette or an adaptive palette

from PIL import Image
oldimage = Image.open("oldimage.png")
palettedata = [0, 0, 0, 102, 102, 102, 176, 176, 176, 255, 255, 255]
expanded_palettedata = palettedata * 64
newimage = oldimage.convert('P', dither=Image.NONE, palette=palettedata)
newimage.show()

如何在不抖动的情况下自动将图像转换为特定的调色板?我想避免在Python中处理每个像素的解决方案,如 John La Rooy的回答及其评论中所述,因为我以前的解决方案涉及用Python编写的内部循环,对于大型图像来说已经证明明显很慢。

How do I automatically convert an image to a specific palette without dithering? I would like to avoid a solution that processes each individual pixel in Python, as suggested in John La Rooy's answer and comments thereto, because my previous solution involving an inner loop written in Python has proven to be noticeably slow for large images.

推荐答案

PIL的部分内容在C中实现的是 PIL._imaging 模块,在 Image.core 使用>来自PIL导入图像。
当前版本的Pillow为每个 PIL.Image.Image 实例提供一个名为 im 的成员,这是一个实例 ImagingCore ,在 PIL._imaging 中定义的类。
您可以使用 help(oldimage.im)列出其方法,但这些方法本身在Python中没有记录。

The parts of PIL implemented in C are in the PIL._imaging module, also available as Image.core after you from PIL import Image. Current versions of Pillow give every PIL.Image.Image instance a member named im which is an instance of ImagingCore, a class defined within PIL._imaging. You can list its methods with help(oldimage.im), but the methods themselves are undocumented from within Python.

ImagingCore 对象的 convert 方法在 _imaging.c
它需要一到三个参数并在<$ c $中创建一个新的 ImagingCore 对象(称为 Imaging_Type c> _imaging.c )。

The convert method of ImagingCore objects is implemented in _imaging.c. It takes one to three arguments and creates a new ImagingCore object (called Imaging_Type within _imaging.c).


  • mode (必填):模式字符串(例如P

  • dither (可选,默认为0):PIL传递0或1

  • paletteimage (可选): ImagingCore 带调色板

  • mode (required): mode string (e.g. "P")
  • dither (optional, default 0): PIL passes 0 or 1
  • paletteimage (optional): An ImagingCore with a palette

我面临的问题是 quantize() in dist-packages / PIL / Image.py 强制 dither 参数为1.
所以我删除了 quantize()方法的副本并更改了它。
这可能不适用于Pillow的未来版本,但如果没有,他们可能会在 quantze()承诺。

The problem I was facing is that quantize() in dist-packages/PIL/Image.py forces the dither argument to 1. So I pulled a copy of the quantize() method out and changed that. This may not work in future versions of Pillow, but if not, they're likely to implement the "extended quantizer interface in a later version" that a comment in quantize() promises.

#!/usr/bin/env python3
from PIL import Image

def quantizetopalette(silf, palette, dither=False):
    """Convert an RGB or L mode image to use a given P image's palette."""

    silf.load()

    # use palette from reference image
    palette.load()
    if palette.mode != "P":
        raise ValueError("bad mode for palette image")
    if silf.mode != "RGB" and silf.mode != "L":
        raise ValueError(
            "only RGB or L mode images can be quantized to a palette"
            )
    im = silf.im.convert("P", 1 if dither else 0, palette.im)
    # the 0 above means turn OFF dithering

    # Later versions of Pillow (4.x) rename _makeself to _new
    try:
        return silf._new(im)
    except AttributeError:
        return silf._makeself(im)

palettedata = [0, 0, 0, 102, 102, 102, 176, 176, 176, 255, 255, 255]
palimage = Image.new('P', (16, 16))
palimage.putpalette(palettedata * 64)
oldimage = Image.open("School_scrollable1.png")
newimage = quantizetopalette(oldimage, palimage, dither=False)
newimage.show()

这篇关于使用PIL将图像转换为特定调色板而不抖动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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