【问题标题】:Why does Pillow convert return colours outside the specified palette?为什么枕头转换返回指定调色板之外的颜色?
【发布时间】:2019-04-01 04:01:53
【问题描述】:

使用 Pillow 5.4.1、Python 3.6.8

给定一个具有 9 种不同颜色的图像 image.png,并给定一个具有 5 种不同颜色的数据调色板,人们会期望要求 pillow 将图像缩小为所描述的调色板,结果图像将仅包含来自该调色板的颜色调色板。

但是,使用im.im.convert 方法会返回一个颜色超出指定调色板的图像;特别是它们总是灰度图像(R==B==G 值)

示例代码,为原始图像、调色板和转换后的图像输出一组独特的颜色。

from PIL import Image
im = Image.open("image.png")

# create palette from raw data
# colours: Red, Green, Blue, Black, and White (5 total)
RGBBW = [(255,0,0), (0,255,0), (0,0,255), (0,0,0), (255,255,255)]
data = sum([list(x) for x in RGBBW], [])[:256]
pimg = Image.new("P",(16,16))
pimg.putpalette(data)

# Hack
im.convert("RGB")
cim_ = im.im.convert("P", 0, pimg.im)
cim = im._new(cim_).convert("RGB")

def colors(im):
    cs = []
    for x in range(im.width):
        for y in range(im.height):
            cs.append(im.getpixel((x,y)))
    return list(set(cs))

print("Original: %s" % colors(im))
print("Palette: %s" % RGBBW)
print("Convert: %s" % colors(cim))

输入图像:->

(较大版本,仅用于可视化:

输出:

Original: [(85, 85, 85, 255), (0, 0, 255, 255), (0, 0, 0, 255), (255, 0, 0, 255), (0, 255, 255, 255), (255, 255, 255, 255), (255, 255, 0, 255), (255, 0, 255, 255), (0, 255, 0, 255)]
Palette: [(255, 0, 0), (0, 255, 0), (0, 0, 255), (0, 0, 0), (255, 255, 255)]
Convert: [(252, 252, 252), (0, 0, 255), (255, 0, 0), (0, 0, 0), (170, 170, 170), (0, 255, 0), (84, 84, 84)]

(请注意,防止抖动的hack 是一种解决方法,等待我为master 贡献的修复(尚未被切入新版本))

[(170, 170, 170), (84, 84, 84), (252, 252, 252)] 出现在转换后的图像中,但未在原始调色板中指定。它们都恰好是灰度的。

我认为src/libImaging/Palette.c 中的某些东西会影响这一点,但我不确定这是代码的错误,还是 libjpeg 的“功能”

【问题讨论】:

  • 请分享您的输入图像。
  • @MarkSetchell 输入图像添加(放大版本,实际上是可见的。)。您链接到的另一个问题是我已经看到的,它不能解决我的问题,但它确实有助于修复抖动错误upstream
  • 我认为是Palette.c 的第 47 行(您链接到的)正在为您服务。它用灰度值填充调色板中未使用的条目并随意使用它们!跨度>
  • 我不太担心信用问题——主要是解决问题。随意写下来并接受您自己的答案。如果您让 PIL/Pillow 团队因此做出任何更改或更新,请在此处发布链接。祝你的项目好运!

标签: python python-imaging-library palette


【解决方案1】:

原来这个问题既是用户错误,也是意外的初始化问题。

初始化问题:作为pointed out in the comments,新图像的调色板是specifically initialised as greyscale

如果我们用自己的调色板替换整个调色板,那就没问题了。除了,我不是。

data = sum([list(x) for x in RGBBW], [])[:256]

这行逻辑不正确。

调色板需要一个扁平列表,最多包含 256 个 RGB 三元组,即一个最大长度为 768 的数组。如果该数组小于这个值,那么其余的灰度仍将起作用。

重新初始化调色板的更好方法是确保我们重复一个值以覆盖灰度。

在这种情况下:

data = (sum([list(x) for x in RGBBW], []) + (RGBBW[-1] * (256 - len(RGBBW))))[:256*3]

即:

data = (
    sum([list(x) for x in RGBBW], []) # flatten the nested array
    + (RGBBW[-1] * (256 - len(RGBBW))) # extend with the last value, to our required length, if needed
    )[:256*3] # and trim back, if needed.

这将导致调色板始终为 768 长度。

使用我们提供的数组中的最后一个值是任意选择,因为它仅用作有效的填充值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多