38.图像语义分割-UNET

目录

1  UNET简介

2  数据集介绍

2.1  labels.py

2.2  展示标注数据集图像

3  代码部分

3.1  导入库

3.2  读取路径

3.3  创建数据集

3.4  定义加载图像函数

3.4.1  concat的用法

3.4.2  tf.image.resize()

3.4.3  回到定义的crop_img()方法

3.4.4  定义翻转方法

3.4.5  定义加载训练图像函数

3.4.6  定义加载测试图像函数

3.5  定义相关变量

3.6  加载图像

3.7  调整数据集

3.8  创建网络

3.8.1  定义下采样层

3.8.2  定义上采样层

3.8.3  定义UNET模型

3.9  编译模型

3.10  训练模型

3.10.1  定义训练步骤

3.10.2  定义测试步骤

3.10.3  定义tensorboard需要的东西

3.10.4  定义检查点需要的东西

3.10.5  定义训练与测试过程

3.11  保存模型

3.12  查看tensorboard

3.13  预测模型


1  UNET简介

UNET的网络类似字母U,所以命名为U-net,UNET的论文地址 https://arxiv.org/abs/1505.04597

在文章的第二页展示了网络的结构

  • 深蓝色箭头进行的是卷积核为(3,3)的卷积操作,之后使用relu激活
  • 灰色箭头使用的是方法是复制和裁剪,我们可以看到最下面的灰色箭头,他把图像从(64,64,512)转换为(56,56,512),这个操作有点儿麻烦,我们在其他操作中不改变图像的大小,在这里我们使用tf.concat对两张图像进行加和,虽然从方法上来讲都叫跳接,但是此处的跳接与FCN中的tf.add有区别
  • 红色箭头使用的是池化核为(2,2)的最大池化操作
  • 绿色箭头使用的是卷积核为(2,2)的反卷积操作
  • 浅蓝色箭头使用的是卷积核为(1,1)的卷积操作

2  数据集介绍

我们这次使用的数据集为城市街景数据集,命名为Cityscapes_dataset

数据集由5个部分组成

在images中放的是街景未标注时的图像,images中下面有两个文件夹,分别是train与val

在train和val分别又有不同的文件夹,文件夹名称是城市的名称

在数据集根路径下的test,train,val放的都是不同城市街景的标注文件,其中_gtFine_color代表彩色分割图,_gtFine_instancelds代表实例分割图,_gtFine_labelIds代表语义分割的目标图,我们使用的是语义分割的目标图

我们绘制一下数据集中图像文件的关系

2.1  labels.py

最后我们来看labels.py,这个数据集默认有34个标签,34个标签种类名称对应下面的name,在本次项目中,我们没有使用到labels.py

在我们训练的过程中可以使用labels.py挑选我们需要的标签,我们可以使用种类为19种的标签(把某些种类的标签合并了)

0,1,2,3,4,5,6,9,10,14,15,16,18,29,30 这些种类我们定义ID为255

7 我们定义为0

8 我们定义为1

11 我们定义为2

12 我们定义为3

13 我们定义为4

17 我们定义为5

19 我们定义为6

20 我们定义为7

21 我们定义为8

22 我们定义为9

23 我们定义为10

24 我们定义为11

25 我们定义为12

26 我们定义为13

27 我们定义为14

28 我们定义为15

31 我们定义为16

32 我们定义为17

33 我们定义为18

-1 我们定义为-1

后面还有一个7分类的,分类方法和上面相似

2.2  展示标注数据集图像

最后我们把两种图像打开看一下,两种图像高都为1024,宽都为2048,原始图像3通道,标注图像1通道

  • 原始图像

  • 标注图像

3  代码部分

3.1  导入库

3.2  读取路径

首先我们读取训练数据的路径

此处提取标签的时候,我们只需要结尾为 _gtFine_labelIds.png 的文件,所以我们这样写

  • 都是用glob.glob方式提取出来的路径,原图像和标注图像是一一对应的

之后我们定义测试数据(验证数据)

3.3  创建数据集

3.4  定义加载图像函数

我们有两种图像,一种是原始图像,一种是标注图像,我们依然使用两种加载图像的方式

在下一步中我们加入数据增强,这里加入数据增强的时候要注意,如果使用翻转这些操作,不能让两张对应的图像执行不同的操作,比如说原始图像是正着的,标注图像是倒着的,这样就会极大的影响结果,所以我们不能直接使用之前数据增强使用的那些直接随机的方法(random_crop,random_flip_left_right,random_flip_up_down这些)

如果我们一定需要随机裁剪,为保证随机裁剪后我们的图像仍能一一对应,所以我们要先把原始图像与标注图像先合起来,之后再对其进行随机裁剪

我们现在定义一个随机裁剪的函数

3.4.1  concat的用法

这里首先用到了concat,concat是把两张图像加在一起的函数,第一个参数我们很好理解,要相加的两张图像,我们现在看一下第二个参数axis

我们看一下文档中的例子

  • axis = 0

t1,t2的shape是(2,3),当axis为0的时候结果shape是(4,3)

  • axis = 1

t1,t2的shape是(2,3),当axis为1的时候结果shape是(2,6)

  • axis = -1

我们最后自己测试一下axis = -1

这样我们的答案就很明显了,axis是几维,结果就是几维相加,我们是要做到通道的那一个维度相加,所以我们令axis为-1,我们在上面那个函数的结果的形状为(1024,2048,4)

此次相加并不会对图像中的内容产生影响,它像是电影《无双》中把3层古画叠起来的操作,有兴趣的话可以看一下这个电影的片段,方便理解 无双:一幅名画让老大开窍,三张纸叠在一起组成一副,这就是中国的水墨画!_腾讯视频

3.4.2  tf.image.resize()

concat的下面我们使用了resize,第一个参数是要改变大小的对象,第二个是要改变为的大小,method是变化的方法,我们当前使用的方法为最近邻插值法

如果相对方法深入了解可以看一下这个 tensorflow image类图像操作Ops之大小重调和图像标注框(二)_wuguangbin1230的博客-CSDN博客

3.4.3  回到定义的crop_img()方法

  • 返回值如果在第三个维度不加冒号,就变成了切片,切片之后第三个维度就会消失,图像只会保留宽高两个维度
  • 此时可以使用plt.imshow()展示图像,plt.imshow()只接收三通道(RGB),四通道(RGBA)或者二维的图像

经过相加与改变大小,接下来我们可以使用随机裁剪,之后返回值第一个为原始图像,第二个为标注图像

3.4.4  定义翻转方法

tf.random.uniform(())会生成一个0到1之间的值,如果这个值大于0.5,我们对img与mask同时进行左右翻转

3.4.5  定义加载训练图像函数

先读取原图像,再读取标注图像,之后再进行随机裁剪,之后再进行随机翻转,之后对原始图像进行归一化,再之后改变标注图像的格式,由于标注图像是作为label存在的,所以我们要将其改为int格式

3.4.6  定义加载测试图像函数

此时数据我们不需要进行图像增强,也就是说不需要进行随机裁剪与翻转,由于之前的resize是在随机裁剪的时候做的,此处不进行随机裁剪,所以此处要进行resize

3.5  定义相关变量

这些我们之前都使用过

唯一注意的一点是,如果机器不足以支撑足够多的BUFFER_SIZE,我们就需要在前面将原始图像与标注图像的路径进行乱序

3.6  加载图像

此处我们用plt看一下

发现加载图像部分没有什么问题

3.7  调整数据集

3.8  创建网络

3.8.1  定义下采样层

下图中每一个红圈都进行了一次下采样,一次最大池化,两次卷积,,由于我们使用的次数较多,我们将其合成为一个自定义层

  • 由于我们要使用到下采样的结果进行跳接,所以我们不能将下采样层定义为先卷积,后池化

我们的卷积与图示中有区别,为了让灰色箭头的操作能简单进行,我们在这里padding使用same

为了能更好的复用代码,所以我们区分是否接入池化的情况

3.8.2  定义上采样层

上采样是我们下图中的画红圈的部分,两层卷积,一层反卷积

我们可以看到反卷积之前的图像厚度是反卷积之后图像厚度的2倍,所以他的units一定是卷积操作的一半,反卷积前的图像大小为反卷积后的图像大小的二倍,所以此处的strides为2,图像大小就正好是反卷积前的一半,所以padding此处我们使用same

3.8.3  定义UNET模型

首先我们先把需要的层定义出来

  • 下采样层是否池化会在下面的前向传播中进行定义

之后定义前向传播

流程和下面这个图一样

后面我们使用自定义训练

3.9  编译模型

首先我们将模型实例化

之后定义优化器与损失函数

之后定义评价指标,我们使用IoU作为评价指标,tensorflow内置了一个平均lou的方法,直接使用会报shape不一致的错误,我们改一下Iou,参考链接 Tensorflow中tf.keras.metrics.MeanIoU在shape不一致错误_Bluish White的博客-CSDN博客

之后定义每个epoch的平均loss与acc

之后使用iou

之后我们定义测试指标

3.10  训练模型

3.10.1  定义训练步骤

3.10.2  定义测试步骤

3.10.3  定义tensorboard需要的东西

3.10.4  定义检查点需要的东西

之后我们在项目路径下创建名为checkpoint_file的文件夹

3.10.5  定义训练与测试过程

3.11  保存模型

这里使用的是自定义模型,所以我们不能将其变为.h5文件

3.12  查看tensorboard

在预测模型之前我们先看一下tensorboard

我们先看一下分类的正确情况,发现最终在80%以上

之后我们再看一下iou情况

iou是 实际区域与预测区域的交集面积 除 实际区域与预测区域的并集面积

再之后是loss

通过这三组数据,我们可以发现效果并不是很好,但是还可以看

3.13  预测模型

我们首先从网上搞一张街景图片

导入库后我们读取模型,之后定义读取图像函数

  • 这里读取图像不能使用图运算

之后我们定义预测函数,预测函数与 36.图像语义分割-FCN_potato123232的博客-CSDN博客 中的预测函数相同

之后我们对图像进行预测

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Suyuoa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值