如何使用 Python 和 Pillow 将此索引 PNG 转换为灰度并保持透明度?
How to convert this indexed PNG to grayscale and keep transparency, using Python and Pillow?
我正在尝试使用 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)
无论使用哪种方法,图像中的所有黑色都变得透明。
我想了解我在这里遗漏了什么,或者这是 Pillow 中的一些错误或限制。仔细研究一下图像调色板,我会说透明度实际上分配给了调色板中的黑色。例如,如果我将它转换为 RGBA 模式,外面就会变成黑色。所以一定是有别的东西让外面的区域透明了。
有什么建议吗?
Digging a little through the image palette, I would say that transparency is in fact assigned to the black color in the palette.
pngcheck
告诉我事实并非如此:
...
chunk PLTE at offset 0x00025, length 48: 16 palette entries
chunk tRNS at offset 0x00061, length 1: 1 transparency entry
每种 实际 颜色在 PLTE
中都有一个索引,包括黑色,并且还有一个指定为 "transparent" 的附加条目。黑色环境可能是先前转换之一的人工制品,其中 alpha=0 被转换为 RGBA (0,0,0,0)。
Pillow 立即转换为 Lab("L" 和 "LA")似乎无法处理索引颜色转换。
您可以通过先将图像转换为 RGBA,然后使用来自 the documentation 的 Lab 转换公式将 RGBA 的每个像素四元组转换为灰色,然后将其转换回调色板来解决此问题:
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')
(硬编码假设您的输入图像确实是一个索引文件。如果您想确定,请添加检查。)
结果,包裹在注释块中,因此您可以看到透明度:
找不到将我的 .png“编入索引”或使用调色板的方法。最后做的是:
- 保存 Alpha 通道
- 转换为“L”然后返回“RGB”
- 重新应用 Alpha 通道(又名透明度)
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)
可能效率不高,但可以完成工作
我正在尝试使用 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)
无论使用哪种方法,图像中的所有黑色都变得透明。
我想了解我在这里遗漏了什么,或者这是 Pillow 中的一些错误或限制。仔细研究一下图像调色板,我会说透明度实际上分配给了调色板中的黑色。例如,如果我将它转换为 RGBA 模式,外面就会变成黑色。所以一定是有别的东西让外面的区域透明了。
有什么建议吗?
Digging a little through the image palette, I would say that transparency is in fact assigned to the black color in the palette.
pngcheck
告诉我事实并非如此:
...
chunk PLTE at offset 0x00025, length 48: 16 palette entries
chunk tRNS at offset 0x00061, length 1: 1 transparency entry
每种 实际 颜色在 PLTE
中都有一个索引,包括黑色,并且还有一个指定为 "transparent" 的附加条目。黑色环境可能是先前转换之一的人工制品,其中 alpha=0 被转换为 RGBA (0,0,0,0)。
Pillow 立即转换为 Lab("L" 和 "LA")似乎无法处理索引颜色转换。
您可以通过先将图像转换为 RGBA,然后使用来自 the documentation 的 Lab 转换公式将 RGBA 的每个像素四元组转换为灰色,然后将其转换回调色板来解决此问题:
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')
(硬编码假设您的输入图像确实是一个索引文件。如果您想确定,请添加检查。)
结果,包裹在注释块中,因此您可以看到透明度:
找不到将我的 .png“编入索引”或使用调色板的方法。最后做的是:
- 保存 Alpha 通道
- 转换为“L”然后返回“RGB”
- 重新应用 Alpha 通道(又名透明度)
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)
可能效率不高,但可以完成工作