使用 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 的“功能”
最佳答案
原来这个问题既是用户错误又是意外的初始化问题。
初始化问题:As 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。
使用我们提供的数组中的最后一个值是一个任意选择,因为它仅用作有效的填充值。
关于python - 为什么 Pillow 会转换指定调色板之外的返回颜色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55447943/