如何用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
相关产品推荐
相关产品推荐

