技术博客丨动手实践系列: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)

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

相关资讯

百分点认知智能实验室:智能对话技术应用和实践

编者按智能对话系统因其巨大的潜力和商业价值受到越来越多研究者和从业者的关注,对话的主要种类包括闲聊型、知识型、任务型、阅读理解型等,目前已经广泛应用在智能客服、智能音箱、智能车载等众多场景。近年来,智能对话还出现了新的应用场景,例如可以将自然语言转换为各种程序性语言,如SQL,从数据库中找到相应的答案,让用户和数据库的交互变得更加直接和方便。为此,Datafun发布了百分点首席算法科学家苏海波署名文章,文中主要介绍了智能问答中的问题语义等价模型、知识图谱问答模型、NL2SQL模型,以及百分点在智能问答领域的实践案例

刷新50多个NLP任务基准,并登顶SuperGLUE全球榜首,百度ERNIE 3.0知识增强大模型显威力

百度 ERNIE 3.0 不仅一举刷新 54 个中文 NLP 任务基准,而且进一步挖掘大规模预训练模型的潜力,首次在百亿级预训练模型中引入大规模知识图谱。

有证据了,MIT表明:大型语言模型≠随机鹦鹉,确实能学到语义

大型语言模型能否捕捉到它们所处理和生成的文本中的语义信息?这一问题在计算机科学和自然语言处理领域一直存在争议。然而,MIT的一项新研究表明,仅基于文本形式训练、用于预测下一个token的语言模型确实能学习和表示文本的意义。