图像分割必备知识点

2023-11-18

文章转自:微信公众号【机器学习炼丹术】。文章转载或者交流联系作者微信:cyx645016617

Unet其实挺简单的,所以今天的文章并不会很长。
喜欢的话可以参与文中的讨论、在文章末尾点赞、在看点一下呗。

0 概述

语义分割(Semantic Segmentation)是图像处理和机器视觉一个重要分支。与分类任务不同,语义分割需要判断图像每个像素点的类别,进行精确分割。语义分割目前在自动驾驶、自动抠图、医疗影像等领域有着比较广泛的应用。

上图为自动驾驶中的移动分割任务的分割结果,可以从一张图片中有效的识别出汽车(深蓝色),行人(红色),红绿灯(黄色),道路(浅紫色)等

Unet可以说是最常用、最简单的一种分割模型了,它简单、高效、易懂、容易构建、可以从小数据集中训练。

Unet已经是非常老的分割模型了,是2015年《U-Net: Convolutional Networks for Biomedical Image Segmentation》提出的模型

论文连接:https://arxiv.org/abs/1505.04597

在Unet之前,则是更老的FCN网络,FCN是Fully Convolutional Netowkrs的碎屑,不过这个基本上是一个框架,到现在的分割网络,谁敢说用不到卷积层呢。 不过FCN网络的准确度较低,不比Unet好用。现在还有Segnet,Mask RCNN,DeepLabv3+等网络,不过今天我先介绍Unet,毕竟一口吃不成胖子。

1 Unet

Unet其实挺简单的,所以今天的文章并不会很长。

1.1 提出初衷(不重要)

  1. Unet提出的初衷是为了解决医学图像分割的问题;
  2. 一种U型的网络结构来获取上下文的信息和位置信息;
  3. 在2015年的ISBI cell tracking比赛中获得了多个第一,一开始这是为了解决细胞层面的分割的任务的

1.2 网络结构

这个结构就是先对图片进行卷积和池化,在Unet论文中是池化4次,比方说一开始的图片是224x224的,那么就会变成112x112,56x56,28x28,14x14四个不同尺寸的特征。然后我们对14x14的特征图做上采样或者反卷积,得到28x28的特征图,这个28x28的特征图与之前的28x28的特征图进行通道伤的拼接concat,然后再对拼接之后的特征图做卷积和上采样,得到56x56的特征图,再与之前的56x56的特征拼接,卷积,再上采样,经过四次上采样可以得到一个与输入图像尺寸相同的224x224的预测结果。

其实整体来看,这个也是一个Encoder-Decoder的结构:

Unet网络非常的简单,前半部分就是特征提取,后半部分是上采样。在一些文献中把这种结构叫做编码器-解码器结构,由于网络的整体结构是一个大些的英文字母U,所以叫做U-net。

  • Encoder:左半部分,由两个3x3的卷积层(RELU)再加上一个2x2的maxpooling层组成一个下采样的模块(后面代码可以看出);
  • Decoder:有半部分,由一个上采样的卷积层(去卷积层)+特征拼接concat+两个3x3的卷积层(ReLU)反复构成(代码中可以看出来);

在当时,Unet相比更早提出的FCN网络,使用拼接来作为特征图的融合方式。

  • FCN是通过特征图对应像素值的相加来融合特征的;
  • U-net通过通道数的拼接,这样可以形成更厚的特征,当然这样会更佳消耗显存;

Unet的好处我感觉是:网络层越深得到的特征图,有着更大的视野域,浅层卷积关注纹理特征,深层网络关注本质的那种特征,所以深层浅层特征都是有格子的意义的;另外一点是通过反卷积得到的更大的尺寸的特征图的边缘,是缺少信息的,毕竟每一次下采样提炼特征的同时,也必然会损失一些边缘特征,而失去的特征并不能从上采样中找回,因此通过特征的拼接,来实现边缘特征的一个找回。

2 为什么Unet在医疗图像分割种表现好

这是一个开放性的问题,大家如果有什么看法欢迎回复讨论。

大多数医疗影像语义分割任务都会首先用Unet作为baseline,当然上一章节讲解的Unet的优点肯定是可以当作这个问题的答案,这里谈一谈医疗影像的特点

根据网友的讨论,得到的结果:

  1. 医疗影像语义较为简单、结构固定。因此语义信息相比自动驾驶等较为单一,因此并不需要去筛选过滤无用的信息。医疗影像的所有特征都很重要,因此低级特征和高级语义特征都很重要,所以U型结构的skip connection结构(特征拼接)更好派上用场

  2. 医学影像的数据较少,获取难度大,数据量可能只有几百甚至不到100,因此如果使用大型的网络例如DeepLabv3+等模型,很容易过拟合。大型网络的优点是更强的图像表述能力,而较为简单、数量少的医学影像并没有那么多的内容需要表述,因此也有人发现在小数量级中,分割的SOTA模型与轻量的Unet并没有神恶魔优势

  3. 医学影像往往是多模态的。比方说ISLES脑梗竞赛中,官方提供了CBF,MTT,CBV等多中模态的数据(这一点听不懂也无妨)。因此医学影像任务中,往往需要自己设计网络去提取不同的模态特征,因此轻量结构简单的Unet可以有更大的操作空间。

3 Pytorch模型代码

这个是我自己写的代码,所以并不是很精简,但是应该很好理解,和我之前讲解的完全一致,(有任何问题都可以和我交流:cyx645016617):

import torch
import torch.nn as nn
import torch.nn.functional as F

class double_conv2d_bn(nn.Module):
    def __init__(self,in_channels,out_channels,kernel_size=3,strides=1,padding=1):
        super(double_conv2d_bn,self).__init__()
        self.conv1 = nn.Conv2d(in_channels,out_channels,
                               kernel_size=kernel_size,
                              stride = strides,padding=padding,bias=True)
        self.conv2 = nn.Conv2d(out_channels,out_channels,
                              kernel_size = kernel_size,
                              stride = strides,padding=padding,bias=True)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.bn2 = nn.BatchNorm2d(out_channels)
    
    def forward(self,x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = F.relu(self.bn2(self.conv2(out)))
        return out
    
class deconv2d_bn(nn.Module):
    def __init__(self,in_channels,out_channels,kernel_size=2,strides=2):
        super(deconv2d_bn,self).__init__()
        self.conv1 = nn.ConvTranspose2d(in_channels,out_channels,
                                        kernel_size = kernel_size,
                                       stride = strides,bias=True)
        self.bn1 = nn.BatchNorm2d(out_channels)
        
    def forward(self,x):
        out = F.relu(self.bn1(self.conv1(x)))
        return out
    
class Unet(nn.Module):
    def __init__(self):
        super(Unet,self).__init__()
        self.layer1_conv = double_conv2d_bn(1,8)
        self.layer2_conv = double_conv2d_bn(8,16)
        self.layer3_conv = double_conv2d_bn(16,32)
        self.layer4_conv = double_conv2d_bn(32,64)
        self.layer5_conv = double_conv2d_bn(64,128)
        self.layer6_conv = double_conv2d_bn(128,64)
        self.layer7_conv = double_conv2d_bn(64,32)
        self.layer8_conv = double_conv2d_bn(32,16)
        self.layer9_conv = double_conv2d_bn(16,8)
        self.layer10_conv = nn.Conv2d(8,1,kernel_size=3,
                                     stride=1,padding=1,bias=True)
        
        self.deconv1 = deconv2d_bn(128,64)
        self.deconv2 = deconv2d_bn(64,32)
        self.deconv3 = deconv2d_bn(32,16)
        self.deconv4 = deconv2d_bn(16,8)
        
        self.sigmoid = nn.Sigmoid()
        
    def forward(self,x):
        conv1 = self.layer1_conv(x)
        pool1 = F.max_pool2d(conv1,2)
        
        conv2 = self.layer2_conv(pool1)
        pool2 = F.max_pool2d(conv2,2)
        
        conv3 = self.layer3_conv(pool2)
        pool3 = F.max_pool2d(conv3,2)
        
        conv4 = self.layer4_conv(pool3)
        pool4 = F.max_pool2d(conv4,2)
        
        conv5 = self.layer5_conv(pool4)
        
        convt1 = self.deconv1(conv5)
        concat1 = torch.cat([convt1,conv4],dim=1)
        conv6 = self.layer6_conv(concat1)
        
        convt2 = self.deconv2(conv6)
        concat2 = torch.cat([convt2,conv3],dim=1)
        conv7 = self.layer7_conv(concat2)
        
        convt3 = self.deconv3(conv7)
        concat3 = torch.cat([convt3,conv2],dim=1)
        conv8 = self.layer8_conv(concat3)
        
        convt4 = self.deconv4(conv8)
        concat4 = torch.cat([convt4,conv1],dim=1)
        conv9 = self.layer9_conv(concat4)
        outp = self.layer10_conv(conv9)
        outp = self.sigmoid(outp)
        return outp
    

model = Unet()
inp = torch.rand(10,1,224,224)
outp = model(inp)
print(outp.shape)
==> torch.Size([10, 1, 224, 224])

先把上采样和两个卷积层分别构建好,供Unet模型构建中重复使用。然后模型的输出和输入是相同的尺寸,说明模型可以运行。

参考博客:

  1. https://blog.csdn.net/wangdongwei0/article/details/82393275
  2. https://www.zhihu.com/question/269914775?sort=created
  3. https://zhuanlan.zhihu.com/p/90418337
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图像分割必备知识点 的相关文章

随机推荐

  • 整理了60个 Python 实战例子,拿来即用!

    人生苦短 我用 Python 大家好 最近有一些朋友问我有没有一些 Python 实战小案例 今天我整理排版了一遍 给大家分享一下 喜欢记得点赞 收藏 关注 整理了60个Python小例子 拿来即用 整理了60个 Python 实战例子 拿
  • Ubuntu系统下安装微信

    安装微信实现截图发送图片功能 1 打开终端输入命令 更新软件源 sudo apt get update 2 输入以下命令 一定注意 O 中间是大写字母O 不是0也不是小写o wget O https deepin wine i m dev
  • verilog之状态机详细解释(二)

    一 有限状态机设计的一般步骤 1 逻辑抽象 得出状态转换图 就是把给出的一个实际逻辑关系表示为时序逻辑函数 可以用状态转换表来描述 也可以用状态转换图来描述 这就需要 分析给定的逻辑问题 确定输入变量 输出变量以及电路的状态数 通常是取原因
  • Effective C++ - Implementations

    前言 实现中需要注意的一些问题 尽可能延后变量的定义 尽量少做转型动作 转型语法 尽量避免使用dynamic cast 避免返回handles指向对象内部成分 为异常安全而努力是值得的 透彻了解inlining的里里外外 将文件间的编译依存
  • LaTex将表格居于文档中间

    导入booktabs包 usepackage booktabs 插入表格处 begin table htbp table环境 中换成h 效果相同 centering 表示居中 begin tabular cc 表示两列 toprule 添加
  • 憨批的语义分割重制版2——语义分割评价指标mIOU的计算

    憨批的语义分割重制版2 语义分割评价指标mIOU的计算 注意事项 学习前言 什么是mIOU mIOU的计算 1 计算混淆矩阵 2 计算IOU 3 计算mIOU 计算miou 注意事项 这是针对重构了的语义分割网络 而不是之前的那个 所以不要
  • Ubuntu 开机时间

    1 查看开机启动时间 systemd analyze blame 2 关闭服务 关闭NetworkManager sudo systemctl disable NetworkManager wait online service 网络管理器
  • VM虚拟机 此主机支持Intel VT-x,但Intel VT-x处于禁用状态”

    其实遇到这个问题 我们只需要进主板BIOS中 开启Intel Virtualization Technology选项即可解决 但是由于主板品牌众多 当然设置大同小异 其实花点时间就可以在BIOS中找到Intel Virtualization
  • Python进阶-----面对对象4.0(面对对象三大特征之--继承)

    目录 前言 Python的继承简介 1 什么是继承 2 继承的好处 3 object类 继承的相关用法 1 继承的定义与法则 2 对继承的重写 3 单继承 多层继承 4 多继承 5 多继承重写时调用父类方法 前言 在讲之前 我想说说中国古代
  • 快乐数

    快乐数 happy number 有以下的特性 在给定的进位制下 该数字所有数位 digits 的平方和 得到的新数再次求所有数位的平方和 如此重复进行 最终结果必为1 中文名 快乐数 外文名 happy number 类型 计算方法 属于
  • 列出某个目录下面所有的文件与目录

    import java io File public class wenjian 遍历该对应对应的数组 public static void main String args File file new File d 某银行新规面资料 if
  • Spring-AOP实践 - 统计访问时间

    公司的项目有的页面超级慢 20s以上 不知道用户会不会疯掉 于是老大说这个页面要性能优化 于是 首先就要搞清楚究竟是哪一步耗时太多 我采用spring aop来统计各个阶段的用时 其中计时器工具为StopWatch 文章结构 遇到的问题 创
  • centos7安装nginx 报./configure: error: C compiler cc is not found

    centos7安装nginx 报 configure error C compiler cc is not found CentOS 7 下 安装 nginx 执行配置命令 configure 时提示以下错误 解决 执行以下命令 yum y
  • php伪随机数

    目录 函数介绍 代码测试 考点 1 根据种子预测随机数 2 根据随机数预测种子 函数介绍 mt srand 播种 Mersenne Twister 随机数生成器 mt rand 生成随机数 简单来说mt srand 通过分发seed种子 然
  • 如何学会像优秀程序员一样思考

    如何学会像优秀程序员一样思考 程序员的思考方式比较有意思 并且这些思考方式有时候表现得很好 这些思考方式其实可以概述下 通常包含如下几个点 一切都只是数据 数据本身没有任何意义 如果有意义那么它必须被解释 编程是关于创建和组合抽象 模型是给
  • 内容管理软件——Obsidian、Zettlr学习笔记(附Typora)

    一 Obsidian 1 官网 Obsidian 2 学习教程 Obsidian 中文论坛 3 使用经验 3 1关于markdown常用格式 标题的格式 标题级数 空格 文本内容 这是一段普通的文本 这是一级标题 这是二级标题 这是三级标题
  • ChatGPT在生态保护和可持续发展中的潜在作用如何?

    ChatGPT在生态保护和可持续发展领域具有潜在的重要作用 生态保护和可持续发展是全球性的挑战 涉及到环境保护 资源管理 气候变化应对 生物多样性保护等多个方面 ChatGPT作为一种人工智能技术 可以在以下几个方面发挥积极作用 1 数据分
  • ELK(六)ElasticSearch快速入门_中文分词

    分词 分词就是指将一个文本转化成一系列单词的过程 也叫文本分析 在ElasticSearch中称之为Analysis 举例 我是中国人 gt 我 是 中国人 分词API 指定分词器进行分词 POST analyze analyzer sta
  • 【深度学习】详解 Swin Transformer (SwinT)

    目录 摘要 一 介绍 二 原理 2 1 整体架构 2 1 1 Architecture 2 1 2 Swin Transformer Block 2 2 基于移位窗口的自注意力 2 2 1 非重叠局部窗口中的自注意力 2 2 2 在连续块中
  • 图像分割必备知识点

    文章转自 微信公众号 机器学习炼丹术 文章转载或者交流联系作者微信 cyx645016617 Unet其实挺简单的 所以今天的文章并不会很长 喜欢的话可以参与文中的讨论 在文章末尾点赞 在看点一下呗 0 概述 语义分割 Semantic S