在PASCAL VOC 2012图像分割数据集的分割标签是取值为0~255的灰度图片,为了可视化,需要对每一个标签索引分配相应的rgb分量,从而使得原始的标签分割图片转化为上色后的彩色分割图片。根据VOC数据集的color map生成代码,我们可以知道,主要利用的思想是把每个label index和rgb分量看做一个字节/8位2进制数,然后不断地把最低的三位比特从高到低地放入rbg分量并对label index移位。由于在PASCAL VOC 2012分割数据集中只有21个目标类别(包含背景),类别索引的二进制有效位数为0-4位共5个比特位,最终相当于把label index的0和3位、1和4位以及2位分别放入r、g、b分量中,并且从高位开始摆放。
def bitget(byteval, idx):
return (byteval & 1 << idx) != 0 # 判断输入字节的idx比特位上是否为1
def color_map(N=256, normalized=False):
dtype = 'float32' if normalized else 'uint8'
cmap = np.zeros((N, 3), dtype=dtype)
for i in range(N):
c = i
r = g = b = 0 # 将类别索引和rgb分量都视为8位2进制数,即一个字节
for j in range(8): # 从高到低填入rgb分量的每个比特位
r = r | bitget(c, 0) << (7 - j) # 每次将类别索引的第0位放置到r分量
g = g | bitget(c, 1) << (7 - j) # 每次将类别索引的第1位放置到g分量
b = b | bitget(c, 2) << (7 - j) # 每次将类别索引的第2位放置到b分量
c = c >> 3 # 将类别索引移位
cmap[i] = np.array([r, g, b])
cmap = cmap / 255 if normalized else cmap
return cmap
调用color_map(21),得到VOC12的调色板:
[[ 0 0 0]
[128 0 0]
[ 0 128 0]
[128 128 0]
[ 0 0 128]
[128 0 128]
[ 0 128 128]
[128 128 128]
[ 64 0 0]
[192 0 0]
[ 64 128 0]
[192 128 0]
[ 64 0 128]
[192 0 128]
[ 64 128 128]
[192 128 128]
[ 0 64 0]
[128 64 0]
[ 0 192 0]
[128 192 0]
[ 0 64 128]]
# 在PASCAL VOC 2012上简化版本的color map
# 相当于把i的0、3位放到r分量,i的1、4位放到g分量,i的2位放到b分量
def color_map_v2(num_classes=256, normalized=False):
cmap = np.zeros((num_classes, 3))
for i in range(num_classes):
r, g, b = 0, 0, 0
r = r | (i & 2**0) << (7 - 0) | (i & 2**3) << (6 - 3)
g = g | (i & 2**1) << (7 - 1) | (i & 2**4) << (6 - 4)
b = b | (i & 2**2) << (7 - 2)
cmap[i] = np.asarray([r, g, b])
if normalized:
return cmap / 256
else:
return cmap.astype(np.uint8)
调用color_map_v2(21)后同样得到相同的调色板数组:
[[ 0 0 0]
[128 0 0]
[ 0 128 0]
[128 128 0]
[ 0 0 128]
[128 0 128]
[ 0 128 128]
[128 128 128]
[ 64 0 0]
[192 0 0]
[ 64 128 0]
[192 128 0]
[ 64 0 128]
[192 0 128]
[ 64 128 128]
[192 128 128]
[ 0 64 0]
[128 64 0]
[ 0 192 0]
[128 192 0]
[ 0 64 128]]