动手实践系列:cv语义分割!(代码片段)

Datawhale Datawhale     2023-02-20     469

关键词:

 Datawhale干货 

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

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

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

图像分割可以分为以下三个子领域:语义分割、实例分割、全景分割。

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

01 语义分割中的关键步骤

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

首先,以语义分割任务为例,介绍标签的不同表达形式。

1.1 语义标签图

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

在标签图像中,白色和黑色分别代表边框和背景,而其他不同颜色代表不同的类别:

1.2 单通道掩膜

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

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

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

1.3 Onehot编码

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

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

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)

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, classes

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)

游璐颖

福州大学,datawhale成员

个人博客:https://sonatau.github.io

点击阅读原文直接获取数据集

天池赛题解析:零基础入门语义分割-地表建筑物识别-cv语义分割实战(附部分代码)(代码片段)

...门,我们为本赛题定制了学习方案和学习任务,具体包括语义分割的模型和具体的应用案例。在具体任务中我们将讲解具体工具和使用和完成任务的过程。通过对本方案的完整学习,可以帮助掌握语义分割基本技能。同时我们也... 查看详情

cv语义分割全卷积神经网络fcn(更新ing)(代码片段)

学习总结(1)paper《FullyConvolutionalNetworksforSemanticSegmentation》(2)论文翻译可以参考:https://www.cnblogs.com/xuanxufeng/p/6249834.html(3)当前最成功的图像分割深度学习技术都是基于一个共同 查看详情

pytorch多分类的语义分割(代码片段)

...例没有包含多分类的内容,网上资料比较少,就动手调了一下。segmentation_models.pytorch\\examples\\carssegmentation(camvid).ipynb里写了怎么做单分类的调用,用来检测Camvid数据集中的Ca 查看详情

keras深度学习实战(18)——语义分割详解(代码片段)

...3.实现语义分割模型3.1加载数据集3.2模型构建与训练小结系列链接0.前言在《使用U-Net架构进行图像分割》一节中,我们学习图像分割的基本概念,并且构建了基于U-Net网络模型的图像分割模型,在图像中 查看详情

openmmlab实战营打卡-第六课语义分割(代码片段)

...重要性 2.获取上下文信息3.PSPNet2016四、空洞卷积与DeepLab系列算法1.DeepLab系列2.空洞卷积解决下采样问题 空洞卷积和下采样 3.DeepLab模型 4.条件随机场ConditionalRandomField,CRF 能量函数的意义 5.空间金字塔池化AtrousSpatialPyramidPoolingA... 查看详情

附源码医学图像分割入门实践(代码片段)

...前面的一篇医学图像分割多目标分割(多分类)实践文章记录了笔者在医学图像分割踩坑入门的实践,但当时的源码不够完整。通过博客的评论互动和私信发现有很 查看详情

cv语义分割到工作氛围杂谈

CV语义分割到工作氛围杂谈华人团队颠覆CV!SEEM完美分割一切爆火,一键分割「瞬息全宇宙」Meta的「分割一切」的横空出世,让许多人惊呼CV不存在了。基于这一模型,众网友纷纷做了进一步工作,比如GroundedSAM。   &n... 查看详情

语义分割一文概览主要语义分割网络,fcnunetsegnetdeeplab(代码片段)

目录前言知识一、语义分割与实例分割的区别1.SemanticSegmentation(语义分割):2.InstanceSegmentation(实例分割):二、语义分割一般网络架构各种分割网络讲解:一、FullyConvolutionNetworks(FCNs)全卷积网络二、SegNetSegNet网络结构&#x... 查看详情

语义分割专题语义分割相关工作--fullyconvolutionaldensenet(代码片段)

...eNetsforSemanticSegmentation在本文中扩充了DenseNets,以解决语义分割的问题。在城市场景基准数据集(CamVid和Gatech)上获得了最优异的结果,没有使用进一步的后处理模块(如CRF)和预训练模型。此外&# 查看详情

计算机视觉(cv)基于高层api实现宝石分类(代码片段)

...要的基本问题宝石识别属于图像分类中的一个细分类问题实践平台:百度AI实训平台-AIStudio实践环境:Python3.7,PaddlePaddle2.0(二)、环境配置本实践代码运行的环境配置如下:Python版本为3.7,PaddlePaddle版 查看详情

动手学cv-目标检测入门教程:基本概念(代码片段)

...e🐳CV小组创作的目标检测入门教程。对应开源项目《动手学CV-Pytorch》的第3章的内容,教程中涉及的代码也可以在项目中找到,后续会持续更新更多的优质内容,欢迎⭐️。如果使用我们教程的内容或图片,... 查看详情

语义分割semanticsegmentation和数据集动手学深度学习v2

1.语义分割semanticsegmentation语义分割是类的识别,比如狗和猫;实例分割是实体的分割,比如狗1,狗2,和猫。2.语义分割数据集PascalVOC2012图片分割不能用resize,比如红色表示飞机,如果resize的变成淡红... 查看详情

cv+deeplearning——网络架构pytorch复现系列——basenets(backbones)(代码片段)

引言此系列重点在于复现计算机视觉(分类、目标检测、语义分割)中深度学习各个经典的网络模型,以便初学者使用(深入浅出)!代码都运行无误!!首先复现深度学习经典网络模型(basene... 查看详情

动手学cv-目标检测入门教程4:模型结构(代码片段)

...e🐳CV小组创作的目标检测入门教程。对应开源项目《动手学CV-Pytorch》的第3章的内容,教程中涉及的代码也可以在项目中找到,后续会持续更新更多的优质内容,欢迎⭐️。如果使用我们教程的内容或图片,... 查看详情

python使用cv分割列车测试(代码片段)

查看详情

动手学cv-目标检测入门教程3:锚框(anchor)(代码片段)

...e🐳CV小组创作的目标检测入门教程。对应开源项目《动手学CV-Pytorch》的第3章的内容,教程中涉及的代码也可以在项目中找到,后续会持续更新更多的优质内容,欢迎⭐️。如果使用我们教程的内容或图片,... 查看详情

计算机视觉-语义分割(代码片段)

...底层的特征其实很重要。不只是医学图像,对于二分类的语义分割问题,类UNet结构均取得不错的效果。linknet、largekernel和Tiramisu等模型的效果也不错,但不如类UNet结构本文的内 查看详情

aaai2022|在图像级弱监督语义分割这项cv难题上,字节跳动做到了性能显著提升...

...,第一时间送达论文提出了一种面向图像级标签的弱监督语义分割的激活值调制和重校准方案。该方法利用注意力调制模块挖掘面向分割任务的目标区域,通过补偿分支产生的CAM图校准基准的响应图,得到图像的伪标签,该方法... 查看详情