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

如何用Python为0-30灰度值的黑白图像映射自定义调色板?

解决方案:将单通道索引图转为RGB调色板图像(无嵌套循环)

问题根源

你之前的代码错误在于使用了convert('P', palette=Image.Palette.ADAPTIVE)——这个参数会让PIL根据图像内容生成自适应调色板,完全打乱了原像素索引和目标调色板的对应关系,导致后续putpalette无法正确映射颜色。


方案1:修正PIL实现

核心思路是跳过自适应调色板生成,直接基于原像素索引绑定自定义调色板:

from PIL import Image
import os

CITYSCAPES_PALETTE_MAP = [ 
    [  0,   0,   0],   # unlabeled     =   0u
    [128,  64, 128],   # road          =   1u
    [244,  35, 232],   # sidewalk      =   2u
    [ 70,  70,  70],   # building      =   3u
    [102, 102, 156],   # wall          =   4u
    [190, 153, 153],   # fence         =   5u
    [153, 153, 153],   # pole          =   6u
    [250, 170,  30],   # traffic light =   7u
    [220, 220,   0],   # traffic sign  =   8u
    [107, 142,  35],   # vegetation    =   9u
    [152, 251, 152],   # terrain       =  10u
    [ 70, 130, 180],   # sky           =  11u
    [220,  20,  60],   # pedestrian    =  12u
    [255,   0,   0],   # rider         =  13u
    [  0,   0, 142],   # Car           =  14u
    [  0,   0,  70],   # truck         =  15u
    [  0,  60, 100],   # bus           =  16u
    [  0,  80, 100],   # train         =  17u
    [  0,   0, 230],   # motorcycle    =  18u
    [119,  11,  32],   # bicycle       =  19u
    [110, 190, 160],   # static        =  20u
    [170, 120,  50],   # dynamic       =  21u
    [ 55,  90,  80],   # other         =  22u
    [ 45,  60, 150],   # water         =  23u
    [157, 234,  50],   # road line     =  24u
    [ 81,   0,  81],   # ground        =  25u
    [150, 100, 100],   # bridge        =  26u
    [230, 150, 140],   # rail track    =  27u
    [180, 165, 180],   # guard rail    =  28u
    [  0, 254, 254],   # rail raised   =  29u
    [ 90,  40,  40]    # trackbed      =  30u
]

filepath = "your_image_path.png"
output_dir = "output_dir"

with Image.open(filepath) as img:
    # 确保图像为单通道模式(如'L')
    if img.mode != 'L':
        img = img.convert('L')
    
    # 创建P模式图像,直接复用原像素数据
    pal_img = Image.new('P', img.size)
    pal_img.putdata(img.getdata())
    
    # 展开调色板为一维列表,补全至PIL要求的768位(256*3)
    palette = []
    for rgb in CITYSCAPES_PALETTE_MAP:
        palette.extend(rgb)
    palette += [0] * (768 - len(palette))
    
    pal_img.putpalette(palette, 'RGB')
    
    # 转换为RGB图像
    rgb_img = pal_img.convert('RGB')
    rgb_img.show()
    # rgb_img.save(os.path.join(output_dir, "converted.png"))

方案2:Numpy实现(无循环,效率更高)

利用Numpy数组索引直接完成映射,无需任何循环:

from PIL import Image
import numpy as np
import os

CITYSCAPES_PALETTE_MAP = [ 
    # 保留完整调色板列表
    [  0,   0,   0],   # unlabeled     =   0u
    [128,  64, 128],   # road          =   1u
    ...
    [ 90,  40,  40]    # trackbed      =  30u
]

# 将调色板转为Numpy数组,形状为(31, 3)
palette_np = np.array(CITYSCAPES_PALETTE_MAP, dtype=np.uint8)

filepath = "your_image_path.png"
output_dir = "output_dir"

with Image.open(filepath) as img:
    # 转为单通道Numpy数组
    img_np = np.array(img)
    # 直接通过索引映射生成RGB图像,形状为(H, W, 3)
    rgb_np = palette_np[img_np]
    # 转回PIL图像
    rgb_img = Image.fromarray(rgb_np)
    rgb_img.show()
    # rgb_img.save(os.path.join(output_dir, "converted.png"))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 18:35:00