如何使用Python和Pillow将此索引的PNG转换为灰度并保持透明度? [英] How to convert this indexed PNG to grayscale and keep transparency, using Python and Pillow?

查看:175
本文介绍了如何使用Python和Pillow将此索引的PNG转换为灰度并保持透明度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Python/枕头将图像转换为灰度.我对大多数图像没有困难,但是随后在测试不同的图像时,我从BeeWare项目中找到了这个徽标,我知道已经使用某些图像编辑器对其进行了进一步的编辑,并使用ImageOptim对其进行了压缩.

I am trying to convert images to grayscale using Python/Pillow. I had no difficulty in most images, but then, while testing with different images, I found this logo from the BeeWare project, that I know that has been further edited with some image editor and recompressed using ImageOptim.

图像具有某种透明度(在蜜蜂周围的整个白色区域),但是黑色会变得混乱.这是代码:

The image has some kind of transparency (in the whole white area around the bee), but black color gets messed up. Here is the code:

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

使用任何一种方法,图像中的所有黑色都变为透明.

Using either approach, all the black in the image becomes transparent.

我试图了解我在这里缺少的内容,或者这是否是Pillow中的某些错误或限制.仔细研究一下图像调色板,我会说透明度实际上是分配给调色板中的黑色的.例如,如果我将其转换为RGBA模式,则外部变为黑色.因此,必须有其他东西可以使外部区域透明.

I am trying to understand what I am missing here, or if this is some bug or limitation in Pillow. Digging a little through the image palette, I would say that transparency is in fact assigned to the black color in the palette. For instance, if I convert it to RGBA mode, the outside becomes black. So there must be something else that makes the outside area transparent.

有什么提示吗?

推荐答案

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

Digging a little through the image palette, I would say that transparency is in fact assigned to the black color in the palette.

pngcheck 告诉我事实并非如此:

pngcheck tells me that is not the case:

...
chunk PLTE at offset 0x00025, length 48: 16 palette entries
chunk tRNS at offset 0x00061, length 1: 1 transparency entry

每种 actual 颜色在PLTE中都有一个索引,包括黑色,并且还有一个附加条目被指定为透明".黑色环境可能是先前转换之一的伪像,其中alpha = 0被转换为RGBA(0,0,0,0).

Each actual color has an index in PLTE, including black, and there is an additional entry that is designated "transparent". The black surroundings are probably an artefact of one of the previous conversions, where alpha=0 got translated to RGBA (0,0,0,0).

似乎Pillow立即转换为Lab("L"和"LA")无法处理索引的颜色转换.
您可以通过以下方法解决此问题:首先将图像转换为RGBA,然后使用

It seems Pillow's immediate conversion to Lab ("L" and "LA") cannot handle indexed color conversions.
You can solve this by converting the image to RGBA first, then converting each pixel quadruplet of RGBA to gray using the Lab conversion formula from the documentation, and then converting it back to 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])

但是后来我意识到,既然您是从一幅淡化的图像开始,并且想再次以一张图像结束,那么仅转换调色板会容易得多...

but then I realized that since you start out with a palettized image and want to end up with one again, converting only the palette is much easier ...

#/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')

(硬编码为假定您的输入图像确实是索引文件.如果要确定,请添加检查.)

(Hardcoded to assume your input image is indeed an indexed file. Add checks if you want to make sure.)

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

Result, wrapped inside a comment block so you can see the transparency:

这篇关于如何使用Python和Pillow将此索引的PNG转换为灰度并保持透明度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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