Python 3.x 如何使用Python和Pillow将索引PNG转换为灰度并保持透明度?

Python 3.x 如何使用Python和Pillow将索引PNG转换为灰度并保持透明度?,python-3.x,png,transparency,pillow,alpha-transparency,Python 3.x,Png,Transparency,Pillow,Alpha Transparency,我正在尝试使用Python/Pillow将图像转换为灰度。我在大多数图像中都没有遇到困难,但是,在测试不同的图像时,我从BeeWare项目中找到了这个徽标,我知道它已经通过一些图像编辑器进行了进一步编辑,并使用ImageOptim进行了重新压缩 图像具有某种透明度(在蜜蜂周围的整个白色区域),但黑色会弄乱。代码如下: #/usr/bin/env python3 import os from PIL import Image, ImageFile src_path = os.path.exp

我正在尝试使用Python/Pillow将图像转换为灰度。我在大多数图像中都没有遇到困难,但是,在测试不同的图像时,我从BeeWare项目中找到了这个徽标,我知道它已经通过一些图像编辑器进行了进一步编辑,并使用ImageOptim进行了重新压缩

图像具有某种透明度(在蜜蜂周围的整个白色区域),但黑色会弄乱。代码如下:

#/usr/bin/env python3

import os
from PIL import Image, ImageFile

src_path = os.path.expanduser("~/Desktop/prob.png")
img = Image.open(src_path)
folder, filename = os.path.split(src_path)
temp_file_path = os.path.join(folder + "/~temp~" + filename)


if 'transparency' in img.info:
    transparency = img.info['transparency']
else:
    transparency = None

if img.mode == "P":
    img = img.convert("LA").convert("P")

try:
    img.save(temp_file_path, optimize=True, format="PNG", transparency=transparency)
except IOError:
    ImageFile.MAXBLOCK = img.size[0] * img.size[1]
    img.save(temp_file_path, optimize=True, format="PNG", transparency=transparency)
我也试过:

png_info = img.info

if img.mode == "P":
    img = img.convert("LA").convert("P")

try:
    img.save(temp_file_path, optimize=True, format="PNG", **png_info)
except IOError:
    ImageFile.MAXBLOCK = img.size[0] * img.size[1]
    img.save(temp_file_path, optimize=True, format="PNG", **png_info)
无论使用哪种方法,图像中的所有黑色都会变得透明

我试图理解我在这里遗漏了什么,或者这是否是枕头中的一些缺陷或限制。稍微翻阅一下图像调色板,我会说透明度实际上是分配给调色板中的黑色的。例如,如果我将其转换为RGBA模式,外部将变为黑色。因此,必须有其他东西使外部区域透明

有什么建议吗

稍微翻阅一下图像调色板,我会说透明度实际上是分配给调色板中的黑色的

告诉我情况并非如此:

...
chunk PLTE at offset 0x00025, length 48: 16 palette entries
chunk tRNS at offset 0x00061, length 1: 1 transparency entry
每个实际颜色在
PLTE
中都有一个索引,包括黑色,还有一个指定为“透明”的附加条目。黑色的环境可能是先前转换之一的人工制品,其中alpha=0被转换为RGBA(0,0,0,0)

枕头立即转换为实验室(“L”和“LA”)似乎无法处理索引颜色转换。
您可以通过以下方法解决此问题:首先将图像转换为RGBA,然后使用中的Lab转换公式将RGBA的每个四像素组转换为灰色,然后将其转换回palettized:

for i in range(img.size[0]): # for every pixel:
    for j in range(img.size[1]):
        g = (pixels[i,j][0]*299 + pixels[i,j][1]*587 + pixels[i,j][2]*114)//1000
        pixels[i,j] = (g,g,g,pixels[i,j][3])
但后来我意识到,既然你开始时是一个调色板图像,而最终又想得到一个,那么只转换调色板就容易多了

#/usr/bin/env python3

from PIL import Image, ImageFile

img = Image.open('bee.png')

palette = img.getpalette()
for i in range(len(palette)//3):
    gray = (palette[3*i]*299 + palette[3*i+1]*587 + palette[3*i+2]*114)//1000
    palette[3*i:3*i+3] = [gray,gray,gray]

img.putpalette(palette)
img.save('bee2a.png', optimize=True, format="PNG")

print ('done')
(硬编码以假设输入图像确实是索引文件。如果要确保,请添加检查。)

结果,包装在注释块中,以便可以看到透明度:


找不到方法将my.png“编入索引”或使用调色板。结果是:

  • 保存alpha通道
  • 转换为“L”,然后返回“RGB”
  • 重新应用Alpha通道(也称为透明度)

可能效率不高,但它完成了工作

是的,它按预期工作。不过,我有一个问题。难道我们不能用一个比需要的更大的调色板,用重复的颜色吗?@VictorDomingos:当使用调色板改变时?它是高效的,因为它不需要接触原始像素数据;如果更改调色板,还必须更改像素。我的第一次尝试确实改变了RGB数据,并再次将转换为索引颜色的操作留在枕头上。这也可以优化调色板,因此您可以使用效率较低的方法。
    img_colored = Image.open("transparency.png")
    img_colored.load()
    alpha = img_colored.split()[-1]
    img_grey = img_colored.convert("L").convert("RGB")
    img_grey.putalpha(alpha)