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

如何在TensorFlow中读取PascalVOC索引彩色标签图适配FCN语义分割?

这个问题我之前在做FCN语义分割时也遇到过,核心原因是Pascal VOC的标注PNG是调色板(Palette)模式存储的,PIL和TensorFlow对这类图像的解码逻辑不一样:

  • PIL打开调色板图像时,默认会返回索引模式(mode='P'),转成numpy数组后直接得到0-20的类别索引;
  • 而TensorFlow的tf.image.decode_png默认会把调色板图像解码成RGB格式(3通道),所以你拿到的是0-255的RGB像素值,不是我们需要的类别ID。

下面给两种解决方案,你可以根据标注图的实际格式选择:


方案1:直接解码调色板图像为索引(适用于原始Pascal VOC标注图)

如果你的标注图是Pascal VOC原始的调色板PNG(用PIL打开后img.mode为'P'),可以直接指定channels=1解码,就能得到和PIL完全一致的0-20索引:

def load_voc_label_tf(image_path):
    # 读取标注文件
    file = tf.io.read_file(image_path)
    # 解码为单通道索引图像,指定dtype保持和PIL输出一致
    label = tf.image.decode_png(file, channels=1, dtype=tf.uint8)
    # 去掉多余的通道维度,转为[H, W]形状的张量
    label = tf.squeeze(label, axis=-1)
    # 可选:转为int32类型方便后续模型计算
    label = tf.cast(label, tf.int32)
    return label

方案2:通过颜色映射转换为索引(适用于已转为RGB的标注图)

如果你的标注图已经被转换成了RGB格式(PIL打开后mode='RGB'),就需要借助Pascal VOC固定的颜色-类别映射表来转换。我们可以构建颜色到索引的映射,再用TensorFlow的查找表操作完成转换:

# Pascal VOC官方的类别颜色映射(索引 -> (R, G, B))
VOC_COLOR_MAP = {
    0: (0, 0, 0),        # 背景
    1: (128, 0, 0),      # aeroplane
    2: (0, 128, 0),      # bicycle
    3: (128, 128, 0),    # bird
    4: (0, 0, 128),      # boat
    5: (128, 0, 128),    # bottle
    6: (0, 128, 128),    # bus
    7: (128, 128, 128),  # car
    8: (64, 0, 0),       # cat
    9: (192, 0, 0),      # chair
    10: (64, 128, 0),    # cow
    11: (192, 128, 0),   # diningtable
    12: (64, 0, 128),    # dog
    13: (192, 0, 128),   # horse
    14: (64, 128, 128),  # motorbike
    15: (192, 128, 128), # person
    16: (0, 64, 0),      # pottedplant
    17: (128, 64, 0),    # sheep
    18: (0, 192, 0),     # sofa
    19: (128, 192, 0),   # train
    20: (0, 64, 128)     # tvmonitor
}

# 反转映射:颜色 -> 类别索引
color_to_idx = {v: k for k, v in VOC_COLOR_MAP.items()}

def rgb_to_label_idx(label_rgb):
    # 将RGB值转换为唯一整数(方便哈希查找)
    rgb_flat = tf.reduce_sum(label_rgb * tf.constant([256*256, 256, 1], dtype=tf.uint8), axis=-1)
    # 构建查找表的键值对
    keys = tf.constant([r*256*256 + g*256 + b for r, g, b in color_to_idx.keys()], dtype=tf.uint32)
    values = tf.constant(list(color_to_idx.values()), dtype=tf.int32)
    # 创建静态哈希表
    lookup_table = tf.lookup.StaticHashTable(
        tf.lookup.KeyValueTensorInitializer(keys, values),
        default_value=0  # 默认映射到背景类
    )
    # 查找得到类别索引
    label_idx = lookup_table.lookup(tf.cast(rgb_flat, tf.uint32))
    return label_idx

def load_voc_label_tf_rgb(image_path):
    file = tf.io.read_file(image_path)
    # 解码为RGB图像
    label_rgb = tf.image.decode_png(file, channels=3, dtype=tf.uint8)
    # 转换为类别索引
    label_idx = rgb_to_label_idx(label_rgb)
    return label_idx

验证方法

你可以拿一张标注图测试两种方法的结果是否和PIL一致:

import numpy as np
from PIL import Image

# PIL的结果
with Image.open(image_path) as img:
    pil_label = np.array(img)

# TensorFlow的结果
tf_label = load_voc_label_tf(image_path).numpy()

# 检查是否完全相等
print(np.array_equal(pil_label, tf_label))  # 正确情况下会输出True

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:27:57