图像分割基本知识

news/2024/9/22 23:51:29/

计算机视觉和图像处理

  1. Tensorflow入门
  2. 深度神经网络
  3. 图像分类
  4. 目标检测
  5. 图像分割

    图像分割

    • 一、目标分割
      • 1.1 图像分割的定义
      • 1.2 任务类型
        • 1.2.1 任务描述
        • 1.2.2 任务类型
    • 二、语义分割
      • 2.1 FCN网络
        • 2.1.1网络结构
      • 2.2 Unet网络
    • 三、UNet案例
      • 3.1 数据集获取
        • 3.1.1 设置相关信息
        • 3.1.2 图像展示
        • 3.1.3 数据集生成器
      • 3.2 模型构建
        • 3.2.1 编码部分
        • 3.2.2 解码部分
        • 3.2.3 模型构建
      • 3.3 模型训练
        • 3.3.1 数据集划分
        • 3.3.2 数据获取
        • 3.3.3 模型编译
        • 3.3.4 模型训练
      • 3.4 模型预测

一、目标分割

  • 图像分类旨在判断该图像所属类别
  • 目标检测是在图像分类的基础上,进一步判断图像中的目标具体在图像的什么位置,通常是以外包矩阵的形式表示。
  • 图像分割是目标检测更进阶的任务,目标检测只需要框出每个目标的包围盒,语义分割需要进一步判断图像中哪些像素属于哪个目标。但是,语义分割不区分属于相同类别的不同实例。

1.1 图像分割的定义

计算机视觉领域,图像分割指的是将数字图像细分为多个图像子区域(像素的集合)的过程,并且同一个子区域内的特征具有一定相似性,不同子区域的特征呈现较为明显的差异。

1.2 任务类型

1.2.1 任务描述

我们的目标是输入一个RGB彩色图片或者一个灰度图,然后输出一个包含各个像素类别标签的分割图。
在这里插入图片描述
预测目标可以采用one-hot编码,即为每一个可能的类创建一个输出通道。通过取每个像素点在各个通道的argmax可以得到最终的预测分割图。
在这里插入图片描述

1.2.2 任务类型

目前的图像分割任务主要有两类: 语义分割和实例分割
在这里插入图片描述

  • 语义分割就是把图像中每个像素赋予一个类别标签
    在这里插入图片描述
  • 实例分割,相对于语义分割来讲,不仅要区分不同类别的像素,还需要需要对同一类别的不同个体进行区分。如下图所示,不仅需要进行类别的划分,还要将各个个体划分出来:羊1,羊2,羊3,羊4,羊5等。
    在这里插入图片描述

二、语义分割

2.1 FCN网络

FCN用于图像语义分割,自从该网络提出后,就成为语义分割的基本框架,后续算法基本都是在该网络框架中改进而来。
简而言之,FCN和CNN的区别就是:CNN卷积层之后连接的是全连接层;FCN卷积层之后仍然连卷积层,输出的是与输入大小相同的特征图。

2.1.1网络结构

FCN是一个端到端,像素对像素的全卷积网络,用于进行图像的语义分割。整体的网络结构分为两个部分:全卷积部分和上采样部分。

  1. 全卷积部分
    全卷积部分使用经典的CNN网络(以AlexNet网络为例),并把最后的全连接层换成1x1卷积,用于特征提取。
  2. 上采用部分
    上采样部分将最终得到的特征图上采样得到原图像大小的语义分割结果。
    在这里采用的上卷积方法是反卷积,也叫转置卷积,反卷积是一种特殊的正向卷积,通俗的讲,就是输入补0+卷积。先按照一定的比例通过补0来扩大输入图像的尺寸,再进行正向卷积即可。

2.2 Unet网络

Unet网络是建立再FCNN网络基础上的。
在这里插入图片描述
整个网络由编码部分(左)和解码部分(右)组成,类似于一个大大的u字母,具体介绍如下:

1.编码部分是典型的卷积网络架构

编码部分的主要功能是提取输入图像的特征。通过一系列的卷积层和池化层(通常是最大池化层),编码部分逐渐减少特征图的尺寸,同时增加特征图的深度(即特征图的数量)。

  • 架构中含有一种重复结构,每次重复中有2个3x3卷积层、非线性ReLU层和一个2x2 max pooling层(stride为2)。
  • 每一次下采样后我们都把特征通道的数量加倍。

下采样(编码部分):减少数据点的数量或降低数据的分辨率,用于减少数据量、简化模型训练等

  1. 解码部分也使用了类似的模式:

解码部分的主要功能是恢复特征图的空间分辨率,最终生成与输入图像相同尺寸的分割结果。解码部分通过一系列的上采样操作(如转置卷积或上采样层)和卷积操作来逐步恢复特征图的尺寸。

  • 每一步都首先使用反卷积,每次使用反卷积都将特征通道数量减半,特征图大小加倍。
  • 反卷积过后,将反卷积的结果与编码部分中对应步骤的特征图拼接起来。
  • 编码部分中的特征图尺寸稍大,将其修建过后进行拼接。
  • 对拼接后的map再进行2次3x3的卷积。
  • 最后一层的卷积核大小为1x1,将64通道的特征图转化为特定类比数量的结果。

上采样(解码部分):增加数据点的数量或提高数据的分辨率,用于恢复细节、改善图像质量等。

三、UNet案例

Oxford-IIIT Pet Dataset宠物图像分割数据集,包含37种宠物类别,其中有12种猫的类别和25种狗的类别,每个类别大约有200张图片,所有图像都具有品种,头部ROI和像素级分割的标注,如下图所示:
在这里插入图片描述

import os
from IPython.display import Image,display
from tensorflow.keras.preprocessing.image import load_img
import PIL
from PIL import ImageOps

3.1 数据集获取

3.1.1 设置相关信息

# 图像位置
input_dir = 'segdata/images/'
# 图像路径
input_img_path = sorted([os.path.join(input_dir,fname) for fname in os.listdir(input_dir) if fname.endswith('jpg')])
input_img_path

在这里插入图片描述

# 标注信息
target_dir = 'segdata/annotations/trimaps/'
# 目标值
target_img_path = sorted([os.path.join(target_dir,fname) for fname in os.listdir(target_dir) if fname.endswith('png') and not fname.startswith('.')])
target_img_path

在这里插入图片描述

# 图像大小及类别信息
img_size = (160,160)
batch_size = 32
num_classes = 4

3.1.2 图像展示

display(Image(input_img_path[10]))

在这里插入图片描述

img = PIL.ImageOps.autocontrast(load_img(target_img_path[10]))
display(img)

在这里插入图片描述

3.1.3 数据集生成器

from tensorflow import keras
import numpy as np
# 数据集获取类
class OxfordPets(keras.utils.Sequence):# 初始化def __init__(self,batch_size,img_size,input_img_path,target_img_path):self.batch_size = batch_sizeself.img_size = img_sizeself.input_img_path = input_img_pathself.target_img_path = target_img_path# 迭代次数def __len__(self):return len(self.target_img_path)//self.batch_size # 或者batch数据def __getitem__(self,idx):# 当前批次对应的索引值i = idx * self.batch_size# 图像数据batch_input_img_path = self.input_img_path[i:i+self.batch_size]# 标签数据batch_target_img_path = self.target_img_path[i:i+self.batch_size]# 构建送入网络中图像数据x = np.zeros((self.batch_size,)+self.img_size+(3,),dtype='float32')for j,path in enumerate(batch_input_img_path):img = load_img(path,target_size=self.img_size)# 将PIL图像对象转换成Numpy数组x[j] = keras.preprocessing.image.img_to_array(img)y = np.zeros((self.target_size,) + self.img_size +(1,),dtype='uint8')for j,path in enumerate(batch_target_img_path):img = load_img(path,target_size=self.img_size,color_mode="grayscale")# 再数组的末尾增加一个维度y[j] = np.expand_dims(img,2)return x,y

3.2 模型构建

import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.layers import Input,Conv2D,Conv2DTranspose
from tensorflow.keras.layers import MaxPooling2D,Cropping2D,Concatenate,ZeroPadding2D
from tensorflow.keras.layers import Lambda,Activation,BatchNormalization,Dropout
from tensorflow.keras.models import Model

3.2.1 编码部分

# 下采样:输出张量,卷积核个数
def downsampling_block(input_tensor,filters):# 输入层x = Conv2D(filters,kernel_size=(3,3),padding='same')(input_tensor)# BN层x = BatchNormalization()(x)# 激活层x = Activation('relu')(x)# 卷积x = Conv2D(filters,kernel_size=(3,3),padding='same')(x)# BN层x = BatchNormalization()(x)# 激活层x = Activation('relu')(x)# 返回return MaxPooling2D(pool_size=(2,2))(x),x

3.2.2 解码部分

# 上采样:输入张量,特征融合张量(编码部分产生的特征图),卷积核个数
def upsampling_block(input_tensor,skip_tensor,filters):# 反卷积x = Conv2DTranspose(filters,kernel_size=(3,3),strides=2,padding='same')(input_tensor)# 获取当前特征图的尺寸_,x_hight,x_width,_ = x.shape# 获取特征融合图的尺寸_,s_hight,s_width,_ = skip_tensor.shape# 获取特征图大小差异h_crop = x_hight - s_hightw_crop = x_width - s_width# 若特征图大小相同则不进行裁剪if h_crop == 0 and w_crop ==0:y = skip_tensorelse:cropping = ((h_crop//2,h_crop-h_crop//2),(w_crop//2,w_crop-w_crop//2))y = ZeroPadding2D(cropping=cropping)(skip_tensor)# 特征融合x = Concatenate()([x,y])# 卷积x = Conv2D(filters,kernel_size=(3,3),padding='same')(x)# BN层x = BatchNormalization()(x)# 激活层x = Activation('relu')(x)# 卷积x = Conv2D(filters,kernel_size=(3,3),padding='same')(x)# BN层x = BatchNormalization()(x)# 激活层x = Activation('relu')(x)return x 

3.2.3 模型构建

def unet(imagesize,classes,fetures=64,depth=3):# 定义输入inputs = keras.Input(shape=(img_size)+(3,))x = inputs# ⽤来存放进⾏特征融合的特征图skips=[]# 构建编码部分for i in range(depth):# 下采样x,x0 = downsampling_block(x,fetures)skips.append(x0)# 特征翻倍fetures *=2# 卷积x = Conv2D(fetures,kernel_size=(3,3),padding="same")(x)# BN层x = BatchNormalization()(x)# 激活层x = Activation("relu")(x)# 卷积x = Conv2D(fetures,kernel_size=(3,3),padding='same')(x)# BN层x = BatchNormalization()(x)# 激活层x = Activation("relu")(x)# 构建解码部分for i in reversed(range(depth)):# 深度增加,特征图通道减半fetures //= 2# 下采样x = upsampling_block(x,skips[i],fetures)# 卷积x = Conv2D(fetures,kernel_size=(1,1),padding="same")(x)# 激活outputs = Activation("softmax")(x)# 模型定义model = keras.Model(inputs,outputs)return model
model = unet(img_size,4)
model.summary()

在这里插入图片描述

3.3 模型训练

3.3.1 数据集划分

import random
# 验证集数量
val_sample = 500
# 将数据集打乱
random.Random(100).shuffle(input_img_path)
random.Random(100).shuffle(target_img_path)
# 训练集
train_input_img_path = input_img_path[:-val_sample]
train_target_img_path = target_img_path[:-val_sample]
# 验证集
test_input_img_path = input_img_path[-val_sample:]
test_target_img_path = target_img_path[-val_sample:]

3.3.2 数据获取

train_gen = OxfordPets(batch_size,img_size,train_input_img_path,train_target_img_path)
test_gen = OxfordPets(batch_size,img_size,test_input_img_path,test_target_img_path)

3.3.3 模型编译

model.compile(optimizer=tf.keras.optimizers.RMSprop(),loss=tf.keras.losses.sparse_categorical_crossentropy)

3.3.4 模型训练

model.fit(train_gen,epochs=8,validation_data=test_gen,steps_per_epoch=1,validation_steps=1)

在这里插入图片描述

3.4 模型预测

# predict = model.predict(test_gen)
predictions = []# 获取数据集的大小
steps = len(test_gen)# 分批进行预测
for i in range(steps):# 获取下一个批次的数据batch = next(iter(test_gen))# batch 是一个元组,第一个元素是输入数据,第二个元素是标签batch_inputs, batch_labels = batch# 使用输入数据进行预测batch_predictions = model.predict(batch_inputs)predictions.append(batch_predictions)# 合并所有的预测结果
final_predictions = np.concatenate(predictions, axis=0)

在这里插入图片描述

def display_mask(i):# 获取第i个样本预测结果mask = np.argmax(final_predictions[i],axis=-1)# 扩展维度mask =np.expand_dims(mask,axis=-1)# 将掩码转换为PIL Image对象img = keras.preprocessing.image.array_to_img(mask)# 增强图像对比度img = PIL.ImageOps.autocontrast(img)display(img)
display(Image(filename=test_input_img_path[5]))

在这里插入图片描述

img = PIL.ImageOps.autocontrast(load_img(test_target_img_path[5]))
display(img)

在这里插入图片描述

display_mask(5)

在这里插入图片描述
**人工智能不学也罢,没有个好电脑根本跑不出来,只能降低epoch,降低batch_size,分批次去预测模型,勉强可以训练预测模型,但结果就有点不敬人意了


http://www.ppmy.cn/news/1529059.html

相关文章

Unity自我实现响应式属性

其实只是写着玩,响应式编程建议使用UniRx插件(一套成熟的响应式编程解决方案),我写的主要是借鉴一下这个思想,实现的也不够优雅,不过逻辑也算严密可以正常使用.你可以查看我写的理解响应式属性的思想. 借鉴UniRx的ReactiveProperty类,且UniRx不仅有响应式属性. using System; …

【笔记】第三节 组织与性能

3.1 基本成分 3.2 微观组织特征 0.6-0.8C%碳素钢的组织为珠光体和少量的铁素体。 如何把组织和性能联系起来?德国克虏伯公司的研究——珠光体片间距与渗碳体片层厚度成比例: t s 0 ( ρ 15 ( C % ) − 1 ) ts_0(\frac{\rho}{15(C\%)}-1) ts0​(15(C%)…

分布式计算技术是什么?在数据集成值得作用?

数据是现代科技技术的基础,面对爆炸性数据的增长,要求计算能力要求更高、数据整合和处理更有效,如何应对数据集成带来的挑战?本文将探讨分布式计算技术在数据集成中的优化作用。 一 分布式计算技术。 定义:分布式计算…

[数据结构]无头单向非循环链表的实现与应用

文章目录 一、引言二、线性表的基本概念1、线性表是什么2、链表与顺序表的区别3、无头单向非循环链表 三、无头单向非循环链表的实现1、结构体定义2、初始化3、销毁4、显示5、增删查改 四、分析无头单向非循环链表1、存储方式2、优点3、缺点 五、总结1、练习题2、源代码 一、引…

深度学习----------------------文本预处理

目录 文本预处理读取数据集词源化词表该部分总代码该部分总代码 整合所有功能该部分总代码 文本预处理 文本预处理:把文本当作一个时序序列 将解析文本的常见预处理步骤。 这些步骤通常包括: ①将文本作为字符串加载到内存中。 ②将字符串拆分为词元&…

在线查看 Android 系统源代码 Git repositories on android

在线查看 Android 系统源代码 Git repositories on android 1. Git repositories on android1.1. Android Make Build System1.2. Android Open Source Project Code Review References 1. Git repositories on android https://android.googlesource.com/ 1.1. Android Make …

HarmonyOS鸿蒙开发实战(5.0)自定义全局弹窗实践

鸿蒙HarmonyOS开发实战往期文章必看: HarmonyOS NEXT应用开发性能实践总结 最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通) 非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&am…

求两个数二进制中不同位的数

//求两个数二进制中不同位的数 //编程实现&#xff1a;两个int&#xff08;32位&#xff09;整数m和n的二进制表达中&#xff0c; //有多少个位&#xff08;bit&#xff09;不同&#xff1f; //输入例子 &#xff1a;1999 2299 //输出例子&#xff1a;7 #include<stdio.h>…