You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Pillow将仅含25色的RGB图像无损转为P模式(索引色)

问题描述

我有一张仅包含25种颜色的RGB图像,想要转换为P模式(索引色)来节省存储空间,但转换后图像虽为P模式,颜色数量却从25变成了70:

>>> from PIL import Image
>>> img = Image.open(r"test_rgb2p.png")
>>> img.mode
'RGB'
>>> len(img.getcolors())
25
>>> img = img.convert(mode='P')
>>> img.mode
'P'
>>> len(img.getcolors())
70

我猜测convert方法做了不必要的重采样,毕竟颜色数量不该增加。用GIMP转换同一张图为索引色时,颜色数没变化。请问有没有办法实现RGB到P模式转换且不改变颜色数量?

解决方案

直接调用convert('P')时,PIL默认会使用自适应调色板生成算法,这会额外生成新颜色。要严格保留原图像的25种颜色,需要手动提取现有颜色并创建自定义调色板:

步骤说明

  • 提取原图像的全部颜色集合
  • 基于该集合生成符合P模式要求的调色板
  • 用自定义调色板完成模式转换

实现代码

from PIL import Image

# 打开原RGB图像
img = Image.open(r"test_rgb2p.png")

# 获取图像中所有颜色,maxcolors设为足够大以覆盖全部颜色
color_counts = img.getcolors(maxcolors=1000000)
# 提取纯颜色值,忽略计数
original_colors = [color for _, color in color_counts]

# 构建P模式调色板:将RGB颜色展开为一维列表,不足256色的部分用0填充
palette = []
for r, g, b in original_colors:
    palette.extend([r, g, b])
# 调色板必须是768个元素(256*3),补充缺失部分
palette += [0] * (768 - len(palette))

# 创建P模式图像并设置调色板
indexed_img = Image.new("P", img.size)
indexed_img.putpalette(palette)
# 将原RGB图像内容粘贴到索引图上,自动匹配调色板颜色
indexed_img.paste(img, (0, 0))

# 验证结果
print(indexed_img.mode)          # 输出: P
print(len(indexed_img.getcolors()))  # 输出: 25

关键细节

  • getcolors的maxcolors参数必须设为大于图像实际颜色数的值,否则会返回None
  • P模式的调色板要求是长度为768的一维列表,对应256种RGB颜色,不足部分用0填充即可
  • 通过粘贴方式转换,会严格匹配原图像的颜色到自定义调色板,不会新增额外颜色

内容的提问来源于stack exchange,提问作者mmj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 09:25:42