技术博客丨动手实践系列:CV语义朋分!

作者:游璐颖,福州大学,Datawhale成员 图象朋分是计算机视觉中除了分类和检测外的另一项基本义务,它意味着要将图片根据内容朋分成分别的块。相比图象分类和检测,朋分是一项更精细的工作,因为须要对每一个像素点分类。如下图的街景朋分,由于对每一个像素点都分类,物体的轮廓是精准勾勒的,而不是像检测那样给出边界框。图象朋分可以分为以下三个子领域:语义朋分、实例朋分、全景朋分。 由对比图可发现,语义朋分是从像素层次来识别图象,为图象中的每一个像素制定种别标记,目前广泛应用于医学图象和无人驾驶等;实例朋分相对更具有挑战性,不仅需

作者:游璐颖,福州大学,Datawhale成员 

图象朋分是计算机视觉中除了分类和检测外的另一项基本义务,它意味着要将图片根据内容朋分成分别的块。相比图象分类和检测,朋分是一项更精细的工作,因为须要对每一个像素点分类。

如下图的街景朋分,由于对每一个像素点都分类,物体的轮廓是精准勾勒的,而不是像检测那样给出边界框。

技术博客丨动手实践系列:CV语义朋分!图象朋分可以分为以下三个子领域:语义朋分、实例朋分、全景朋分。 

技术博客丨动手实践系列:CV语义朋分!

由对比图可发现,语义朋分是从像素层次来识别图象,为图象中的每一个像素制定种别标记,目前广泛应用于医学图象和无人驾驶等;实例朋分相对更具有挑战性,不仅须要正确检测图象中的标的,同时还要精确的朋分每一个实例;全景朋分综合了两个义务,要求图象中的每一个像素点都必须被分配给一个语义标签和一个实例id。

01 语义朋分中的关键步骤

在进行网络训练时,时常须要对语义标签图或是实例朋分图进行预处理。如对于一张彩色的标签图,通过色彩映照表得到每种色彩所代表的种别,再将其变换成相应的掩膜或Onehot编码完成训练。这里将会对于其中的关键步骤进行讲解。

首先,以语义朋分义务为例,介绍标签的分别表达形式。

1.1 语义标签图

语义朋分数据集中包括原图和语义标签图,两者的尺寸大小相同,均为RGB图象。

在标签图象中,白色和黑色分别代表边框和背景,而其他分别色彩代表分别的种别:

技术博客丨动手实践系列:CV语义朋分!

1.2 单通道掩膜

每一个标签的RGB值与各自的标注种别对应,则可以很容易地查找标签中每一个像素的种别索引,生成单通道掩膜Mask。

如下面这种图,标注种别包括:Person、Purse、Plants、Sidewalk、Building。将语义标签图变换为单通道掩膜后为右图所示,尺寸大小不变,但通道数由3变为1。

技术博客丨动手实践系列:CV语义朋分!

每一个像素点位置一一对应。

技术博客丨动手实践系列:CV语义朋分! 

1.3 Onehot编码

Onehot作为一种编码方式,可以对每一个单通道掩膜进行编码。

比如对于上述掩膜图Mask,图象尺寸为,标签种别共有5类,我们须要将这个Mask变为一个5个通道的Onehot输出,尺寸为,也就是将掩膜中值全为1的像素点抽取出生成一个图,相应位置置为1,其余为0。再将全为2的抽取出再生成一个图,相应位置置为1,其余为0,以此类推。

技术博客丨动手实践系列:CV语义朋分!

02 语义朋分实践

接下来以Pascal VOC 2012语义朋分数据集为例,介绍分别表达形式之间应该如何相互变换。

实践采用的是Pascal VOC 2012语义朋分数据集,它是语义朋分义务中十分重要的数据集,有 20 类标的,这些标的包括人类、机动车类以及其他类,可用于标的种别或背景的朋分。

数据集开源地址:

https://gas.graviti.cn/dataset/yluy/VOC2012Segmentation

2.1 数据集读取

本次应用格物钛数据平台服务来完成数据集的在线读取,平台支持多种数据集类型,且提供了很多公开数据集便于应用。在应用之前先进行一些必要的准备工作:

Fork数据集:如果须要应用公开数据集,则须要将其先fork到自己的账户。

获取AccessKey:获取应用SDK与格物钛数据平台交互所需的密钥,链接为https://gas.graviti.cn/tensorbay/developer

理解Segment:数据集的进一步划分,如VOC数据集分成了“train”和“test”两个部分。

import os
from tensorbay import GAS
from tensorbay.dataset import Data, Dataset
from tensorbay.label import InstanceMask, SemanticMask
from PIL import Image
import numpy as np
import torchvision
import matplotlib.pyplot as plt

ACCESS_KEY = "<YOUR_ACCESSKEY>"
gas = GAS(ACCESS_KEY)


def read_voc_images(is_train=True, index=0):
    """
read voc image using tensorbay
    """
    dataset = Dataset("VOC2012Segmentation", gas)
    if is_train:
        segment = dataset["train"]
    else:
        segment = dataset["test"]

    data = segment[index]
    feature = Image.open(data.open()).convert("RGB")
    label = Image.open(data.label.semantic_mask.open()).convert("RGB")
    visualize(feature, label)

    return feature, label  # PIL Image


def visualize(feature, label):
    """
visualize feature and label
    """
    fig = plt.figure()
    ax = fig.add_subplot(121)  # 第一个子图
    ax.imshow(feature)
    ax2 = fig.add_subplot(122)  # 第二个子图
    ax2.imshow(label)
    plt.show()

train_feature, train_label = read_voc_images(is_train=True, index=10)
train_label = np.array(train_label) # (375, 500, 3) 

技术博客丨动手实践系列:CV语义朋分!

2.2 色彩映照表

在得到彩色语义标签图后,则可以构建一个色彩表映照,列出标签中每一个RGB色彩的值及其标注的种别。

def colormap_voc():
    """
    create a colormap
    """
    colormap = [[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]]

    classes = ['background', 'aeroplane', 'bicycle', 'bird', 'boat',
                   'bottle', 'bus', 'car', 'cat', 'chair', 'cow',
                   'diningtable', 'dog', 'horse', 'motorbike', 'person',
                   'potted plant', 'sheep', 'sofa', 'train', 'tv/monitor']

    return colormap, class

2.3 Label与Onehot变换

根据映照表,实现语义标签图与Onehot编码的相互变换:

def label_to_onehot(label, colormap):
    """
    Converts a segmentation label (H, W, C) to (H, W, K) where the last dim is a one
    hot encoding vector, C is usually 1 or 3, and K is the number of class.
    """
    semantic_map = []
    for colour in colormap:
        equality = np.equal(label, colour)
        class_map = np.all(equality, axis=-1)
        semantic_map.append(class_map)
    semantic_map = np.stack(semantic_map, axis=-1).astype(np.float32)
    return semantic_map

def onehot_to_label(semantic_map, colormap):
    """
    Converts a mask (H, W, K) to (H, W, C)
    """
    x = np.argmax(semantic_map, axis=-1)
    colour_codes = np.array(colormap)
    label = np.uint8(colour_codes[x.astype(np.uint8)])
    return label

colormap, classes = colormap_voc()
semantic_map = mask_to_onehot(train_label, colormap)
print(semantic_map.shape)  # [H, W, K] = [375, 500, 21] 包括背景共21个种别

label = onehot_to_label(semantic_map, colormap)
print(label.shape) # [H, W, K] = [375, 500, 3]

2.4 Onehot与Mask变换

同样,借助映照表,实现单通道掩膜Mask与Onehot编码的相互变换:

def onehot2mask(semantic_map):
    """
    Converts a mask (K, H, W) to (H,W)
    """
    _mask = np.argmax(semantic_map, axis=0).astype(np.uint8)
    return _mask


def mask2onehot(mask, num_classes):
    """
    Converts a segmentation mask (H,W) to (K,H,W) where the last dim is a one
    hot encoding vector

    """
    semantic_map = [mask == i for i in range(num_classes)]
    return np.array(semantic_map).astype(np.uint8)

mask = onehot2mask(semantic_map.transpose(2,0,1))
print(np.unique(mask)) # [ 0  1 15] 索引相对应的是背景、飞机、人
print(mask.shape) # (375, 500)

semantic_map = mask2onehot(mask, len(colormap))
print(semantic_map.shape) # (21, 375, 500)

更多信息请访问格物钛官网

给TA打赏
共{{data.count}}人
人已打赏
AI

大咖Talk丨崔运凯:AI构造的未来——主动驾驭场景下的制胜环节

2022-1-11 9:35:00

AI

银行流水、财报、年报、电费分割单等各类文档一键提炼,悲观表格提炼东西再升级!

2022-1-11 9:43:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
搜索