面向计算机视觉的深度学习:1~5(4)

简介: 面向计算机视觉的深度学习:1~5(4

面向计算机视觉的深度学习:1~5(3)https://developer.aliyun.com/article/1426860

平均精度均值

mAP 用于评估检测算法。 mAP 度量是检测到的边界框的精度和召回率的乘积。 mAP 值的范围是 0 到 100。数字越大,则越好。 可以通过分别为每个类别计算平均精度AP),然后计算该类别的平均值来计算 mAP。 仅当 mAP 高于 0.5 时,检测结果才被视为真正的阳性。 通过绘制每个类别的绘制精度/召回曲线,可以合并来自测试图像的所有检测。 曲线下的最终区域可用于算法比较。 mAP 是衡量网络灵敏度的一种很好的方法,同时不会引发很多错误警报。 我们已经了解了数据集的评估计法。 接下来,我们将研究定位任务的算法。

定位算法

定位算法是在第 2 章,“图像分类”和第 3 章,“图像检索”中学习的材料的扩展。 在图像分类中,图像经过 CNN(卷积神经网络)的多层。 CNN 的最后一层输出属于每个标签的概率值。 可以扩展它以定位对象。 我们将在以下各节中看到这些想法。

使用滑动窗口定位对象

定位的一种直观方法是使用对象预测图像的多个裁剪部分。 可以通过在图像上移动一个窗口并为每个窗口进行预测来完成图像的裁剪。 移动比图像小的窗口并根据窗口大小裁剪图像的方法称为滑动窗口。 可以对图像的每个裁剪窗口进行预测,这称为滑动窗口对象检测。

可以通过针对紧密裁剪的图像进行图像分类问题训练的深度学习模型来完成预测。 近距离修剪意味着在整个图像中只会找到一个对象。 窗口在整个图像上的移动必须一致。 图像的每个部分都会通过模型以找到分类。 这种方法有两个问题。

  • 它只能找到与窗口大小相同的对象。 如果对象大小大于窗口大小,则滑动窗口将丢失对象。 为了克服这个问题,我们将使用标度空间的概念。
  • 另一个问题是,将窗口移到像素上方可能会导致丢失一些对象。 在每个像素上移动窗口会导致大量额外的计算,因此会降低系统速度。 为避免这种情况,我们将在卷积层中加入一个技巧。

在下一节中,我们将介绍这两种技术。

比例空间概念

比例空间是使用各种大小的图像的概念。 图像会缩小为较小的尺寸,因此可以在相同尺寸的窗口中检测到较大的对象。 可以使用减小的尺寸将图像调整为某些尺寸。 通过删除替代像素或插值来调整图像大小可能会留下一些伪像。 因此,图像被平滑并迭代调整大小。 通过平滑和调整大小获得的图像是比例空间。

窗口在每个刻度上滑动以定位对象。 运行多个比例相当于使用更大的窗口运行图像。 在多个规模上运行的计算复杂度很高。 可以通过以准确率为代价进行快速移动来加快定位速度。 复杂性使解决方案无法在生产中使用。 滑动窗口的思想可以通过完全卷积的滑动窗口实现而变得高效。

将全连接层训练为卷积层

滑动窗口的问题是计算复杂度。 复杂性是因为对每个窗口都进行了预测。 已针对重叠区域的每个窗口计算了深度学习特征。 可以减少裁剪窗口中重叠区域的特征计算。 解决方案是使用仅计算一次特征的全卷积网络。 为了理解全卷积网络,让我们首先看看如何将全连接层转换为convolution_layer。 内核更改为相同的大小,并使用与神经元数量相同的过滤器数量。 也可以对其他层重复此操作。 更改内核大小是将全连接层转换为convolution_layer的简便方法:

convolution_layer_1 = convolution_layer(x_input_reshape, 64)
pooling_layer_1 = pooling_layer(convolution_layer_1)
convolution_layer_2 = convolution_layer(pooling_layer_1, 128)
pooling_layer_2 = pooling_layer(convolution_layer_2)
dense_layer_bottleneck = convolution_layer(pooling_layer_2, 1024, [5, 5])
logits = convolution_layer(dense_layer_bottleneck, no_classes, [1, 1])
logits = tf.reshape(logits, [-1, 10])

密集层表示为卷积层。 这个想法在各种情况下都是强大而有用的。 我们将扩展此思想,以将滑动窗口表示为完整的卷积网络。

滑动窗口的卷积实现

在这种技术中,最终目标不是滑动,而是变成一些需要深度的目标,并需要多个框作为窗口。 Sermanet 等人使用完全卷积实现来克服滑动窗口的这一问题。 这是滑动窗口的这种卷积实现的说明:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SEv6j1Cv-1681567519371)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/615888e7-8aac-425c-83be-0802095b2cd8.png)]

经 Sermanet 等人许可复制。

在示例的上部,常规分类表示为完全卷积层。 在该图的下部,相同的内核应用于更大的图像,最后生成2x2而不是 1。最后一层表示这些边界框的输出中的四个。 具有用于预测的体积可以提高效率,但是盒子仍然存在准确定位的问题。 因此不需要滑动窗口,因此解决了复杂性。 纵横比总是在变化,必须在多个比例尺上看到。 通过完全卷积方法生成的边界框不是很准确。 仅针对额外区域进行额外计算。 可以想像,这些盒子仅限于经过训练的盒子的数量。 接下来,我们将看到一种更准确地检测边界框位置的方法。

将定位视为回归问题

思考定位的一种基本方法是将问题建模为回归问题。 边界框是四个数字,因此可以通过回归设置以直接方式进行预测。 我们还需要预测标签,这是一个分类问题。

有不同的参数化可用于定义边界框。 边界框通常有四个数字。 表示形式之一是坐标的中心以及边界框的高度和宽度。 通过删除全连接层并用回归编码器替换它,可以使用预训练的模型。 必须使用 L2 损失对回归进行正则化,而 L2 损失在异常值方面表现不佳。 L1 的损失比 L1 好。 用平滑化的正则化交换回归更好。 对模型进行微调可提供良好的准确率,而对整个网络进行训练只会带来微不足道的表现改善。 在训练时间和准确率之间进行权衡。 接下来,我们将看到使用卷积网络进行回归的不同应用。

将回归应用于其他问题

回归图像坐标适用于其他几种应用,例如姿态检测基准点检测。 姿势检测是在人体中发现关节位置的动作,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d1XCHgr2-1681567519372)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/9e37fff6-eae3-4729-8cf6-c015a4e0b85f.png)]

在上一个图像中,检测到多个位置,例如头部,颈部,肩膀,脚踝和手。 这可以扩展到所有人类部分。 我们了解到的回归可以用于此应用。 这是基准点检测的示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fZFIj48q-1681567519372)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/6bfd58bb-e261-4dee-8b30-25c3f884e729.png)]

基准点是人脸相对于眼睛,鼻子和嘴唇的位置的地标。 找到这些地标对于基于人脸的增强现实应用至关重要。 人脸识别中还有更多地标可用,将在第 6 章,“相似性学习”中详细介绍。

结合回归与滑动窗口

为滑动窗口方法或完全卷积方法中的每个窗口计算分类分数,以了解该窗口中存在哪些对象。 代替预测用于检测对象的每个窗口的分类得分,可以利用分类得分来预测每个窗口本身。 结合滑动窗口,比例空间,完全卷积和回归之类的所有想法,比任何单独的方法都具有更好的结果。 以下是各种网络使用回归方法在ImageNet数据集上获得的前五个定位错误率:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4oO52SeV-1681567519372)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/e4493c04-62ab-4564-9465-cb134209a626.png)]

上图显示网络越深,结果越好。 对于 AlexNet,定位方法未在本文中描述。 OverFeat 使用带有框合并的多尺度卷积回归。 VGG 使用了定位,但比例尺和位置较少。 这些收益归因于深层特征。 ResNet 使用不同的定位方法和更深入的特征。

回归编码器和分类编码器独立运行。 因此,有可能预测边界框的标签不正确。 通过在不同的层上附加回归编码器可以解决此问题。 该方法也可以用于多个对象,从而解决了对象检测问题。 给定一个图像,找到其中的所有实例。 很难将检测视为回归,因为输出的数量是可变的。 一个图像可能有两个对象,而另一个可能有三个或更多。 在下一节中,我们将看到更有效地处理检测问题的算法。

检测对象

对象检测算法有多种变体。 这里讨论了对象检测 API 附带的一些算法。

卷积神经网络(R-CNN)的区域

该系列的第一个工作是 Girshick 等人提出的 CNN 区域。 它提出了一些框,并检查是否有任何框对应于基本事实。 选择性搜索用于这些地区提案。 选择性搜索通过对各种大小的窗口的颜色/纹理进行分组来建议区域。 选择性搜索寻找斑点样的结构。 它以一个像素开始,并在更大范围内产生斑点。 它产生了大约 2,000 个区域提案。 与所有可能的滑动窗口相比,该区域建议更少。

调整提案的大小并通过标准的 CNN 体系结构,例如 Alexnet/VGG/Inception/ResNet。 CNN 的最后一层是通过 SVM 进行训练的,该 SVM 使用无对象类来标识对象。 通过拉紧图像周围的框可以进一步改善框。 使用对象区域建议训练用于预测更近边界框的线性回归模型。 R-CNN 的架构如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vloYVAlp-1681567519372)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/4f45a709-739b-41a7-969e-56589fecb96f.png)]

经 Girshick 等人许可复制。

编码器可以是标准深度学习模型的预训练模型。 从训练数据为所有区域计算特征。 存储特征,然后训练 SVM。 接下来,用标准化坐标训练边界框。 在图像坐标之外可能会有一些建议,因此将其标准化以进行训练和推理。

这种方法的缺点是:

  • 通过选择性搜索形成了多个建议,因此必须计算许多推论,通常约为 2,000
  • 必须对三个分类器进行训练,这会增加参数的数量
  • 没有端到端的训练

Fast R-CNN

Girshick 等人提出的 Fast R-CNN 方法仅运行一次 CNN 推理,因此减少了计算量。 CNN 的输出用于建议网络并选择边界框。 它介绍了一种称为兴趣区域池的技术。 兴趣区域池采用 CNN 特征,并根据区域将它们合并在一起。 合并使用 CNN 进行推理后获得的特征,并选择区域,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5KceIdjb-1681567519373)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/9607861d-014a-4574-980d-90fb23f91ae4.png)]

经 Girshick 等人许可复制。

这样,执行端到端训练,避免了多个分类器。 请注意,SVM 被 softmax 层替换,并且框回归器由边界框回归器代替。 仍然存在的缺点是选择性搜索,这需要一些时间。

Faster R-CNN

Ren 等人提出了 Faster R-CNN。 Faster R-CNN 和 Fast R-CNN 方法之间的区别在于,Faster R-CNN 使用诸如 VGG 和 Inception 等架构的 CNN 特征来提案而不是选择性搜索。 CNN 特征进一步通过区域提议网络传递。 滑动窗口通过具有潜在边界框和分数的特征传递,并输出一些直观的长宽比,模型输出边界框和分数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mqzq2vzY-1681567519373)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/ea103e8f-b553-4d9d-89cd-077888fb7db0.png)]

经 Ren 等人许可复制。

更快的 R-CNN 比快速 R-CNN 更快,因为它通过仅计算一次特征来节省计算量。

单发多框探测器

SSD(单发多框)是所有方法中最快的。 此方法同时预测对象并找到边界框。 在训练期间,可能会有很多负面因素,因此很难否定地挖掘类别失衡。 CNN 的输出具有各种大小的特征。 这些被传递到3x3卷积过滤器以预测边界框。

此步骤将预测对象和边界框:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HS216cpY-1681567519373)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/28e92ddf-38ea-4b41-80e6-add3753d03d2.png)]

经 Liu 等人许可复制。

这些是可用于对象检测的算法,我们将在下一节中学习如何实现它们。

对象检测 API

Google 发布了经过预先训练的模型,并在COCO数据集上对各种算法进行了训练,以供公众使用。 该 API 建立在 TensorFlow 之上,旨在用于构建,训练和部署对象检测模型。 这些 API 支持对象检测和定位任务。 预训练模型的可用性可对新数据进行微调,从而加快训练速度。 这些不同的模型在速度和准确率之间进行权衡。

安装与配置

使用以下命令安装协议缓冲区(protobuf)编译器。 为 protobuf 创建目录并直接下载该库:

mkdir protoc_3.3
cd protoc_3.3
wget https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip

更改文件夹的权限并提取内容,如下所示:

chmod 775 protoc-3.3.0-linux-x86_64.zip
unzip protoc-3.3.0-linux-x86_64.zip

协议缓冲区(protobuf)是 Google 的语言无关,平台无关的可扩展机制,用于序列化结构化数据。 它用于 XML 的使用,但是更加简单快捷。 模型通常在 TensorFlow 中导出为这种格式。 一个人可以定义一次数据结构,但可以用多种语言进行读写。 然后运行以下命令来编译 protobuf。 返回到工作文件夹,然后从这里克隆存储库,并将它们移至以下文件夹:

git clone https://github.com/tensorflow/models.git

现在,使用以下代码将模型移至研究文件夹:

cd models/research/
~/protoc_3.3/bin/protoc object_detection/protos/*.proto --python_out=.

TensorFlow 对象检测 API 使用 protobuf 导出模型权重和训练参数。 TensorFlow ,模型,研究和苗条目录应通过以下命令附加到PYTHONPATH

export PYTHONPATH=.:./slim/

使用前面的命令添加到 python 路径仅一次。 对于下一个,该命令必须再次运行。 可以通过运行以下代码来测试安装:

python object_detection/builders/model_builder_test.py

此代码的输出在此处给出:

Ran 7 tests in 0.022s
OK

可以从这里获得有关安装的更多信息。 现在安装已完成并经过测试。

预训练模型

有几种模型已经过预先训练并可以使用。 所有这些模型都在COCO数据集上进行了训练,可用于检测COCO数据集中可用的对象,例如人和汽车。 这些模型对于新任务(例如交通标志检测)的迁移学习也很有用。 此处显示了经过预训练的模型的表格,其中包含COCO数据集上的相对速度和 mAP。 使用不同的 CNN 训练了各种算法,并在名称中进行了描述:

模型名称 速度 COCO MAP
ssd_mobilenet_v1_coco 21
ssd_inception_v2_coco 24
rfcn_resnet101_coco 30
faster_rcnn_resnet101_coco 32
faster_rcnn_inception_resnet_v2_atrous_coco 37

根据需求,可以从模型中进行选择。 下载在 Mobilenet 上训练的 SSD 模型,并通过转到工作目录将其提取,如下所示:

mkdir Chapter04 && cd Chapter04
wget http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_11_06_2017.tar.gz
tar -xzvf ssd_mobilenet_v1_coco_11_06_2017.tar.gz

Chapter04文件夹中将包含各种文件,这些文件在此处列出:

  • 这是图的原始定义-graph.pbtxt
  • 图的权重已冻结,可以用于推断-frozen_inference_graph.pb
  • 检查点文件
  • model.ckpt.data-00000-of-00001
  • model.ckpt.meta
  • model.ckpt.index

下一部分将使用此模型执行检测任务。

重新训练对象检测模型

使用相同的 API,我们可以为自定义数据集重新训练模型。 定制数据的训练涉及数据集的准备,选择算法以及执行微调。 整个流水线可以作为参数传递给训练脚本。 训练数据必须转换为 TensorFlow 记录。 TensorFlow 记录是 Google 提供的一种文件格式,可以使数据读取比常规文件更快。 现在,我们将逐步进行训练。

Pet 数据集的数据准备

本示例使用Oxford-IIIT Pet数据集。 使用这些命令从Chapter04目录下载图像和标注。

wget http://www.robots.ox.ac.uk/~vgg/data/pets/daimg.tar.gz
wget http://www.robots.ox.ac.uk/~vgg/data/pets/data/annotations.tar.gz

提取图像和标注,如下所示:

tar -xvf images.tar.gz
tar -xvf annotations.tar.gz

创建pet_tf记录文件以在tf记录中创建数据集,因为它们是对象检测训练器的必需输入。 可在object_detection/data/pet_label_map.pbtxt找到Pet数据集的label_map。 移至research文件夹并运行以下命令:

python object_detection/create_pet_tf_record.py \
 --label_map_path=object_detection/data/pet_label_map.pbtxt \
 --data_dir=~/chapter4/. \
 --output_dir=~/chapter4/.

您可以在研究目录pet_train.recordpet_val.record中看到两个.record文件。

目标检测的训练流水线

训练 protobuf 必须配置为进行训练。 在此过程中,以下五件事很重要:

  • 具有模型类型的模型配置
  • train_config用于标准训练参数
  • 必须报告的指标的eval_config
  • 数据集的train_input_配置
  • 评估数据集的eval_input_配置

我们将使用这个页面中的配置文件。 通过运行以下命令将其下载到Chapter04文件夹。 打开config文件并编辑以下行:

fine_tune_checkpoint: "~/Chapter04/ssd_mobilenet_v1_coco_11_06_2017/model.ckpt"
train_input_reader: {
  tf_record_input_reader {
    input_path: "~/Chapter04/pet_train.record"
  }
  label_map_path: "~/model/research/object_detection/data/pet_label_map.pbtxt"
}
eval_input_reader: {
  tf_record_input_reader {
    input_path: "~/Chapter04/pet_val.record"
  }
  label_map_path: "~/model/research/object_detection/data/pet_label_map.pbtxt"
}

保存config文件。 文件中有各种参数会影响模型的准确率。

训练模型

现在,API,数据和配置文件已准备好进行重新训练。 可以通过以下命令触发训练:

PYTHONPATH=.:./slim/. python object_detection/train.py \
 --logtostderr \
 --pipeline_config_path=~/chapter4/ssd_mobilenet_v1_pets.config \
 --train_dir=~/Chapter04

训练将从大约 140 的损失开始,并将持续减少。 训练将永远进行,必须使用Ctrl + C命令手动将其终止。 训练期间创建的检查点可在以后用于推理。

使用 TensorBoard 监控损失和准确率

训练损失和准确率可以使用 TensorBoard 进行监视。 使用以下命令运行 TensorBoard:

tensorboard --logdir=/home/ubuntu/Chapter04

训练和评估都可以在 TensorBoard 中可视化。

训练自动驾驶汽车的行人检测

可以在这个页面中找到用于训练行人对象检测的数据集。 可以在这个页面中找到检测行人的步骤。 可以从这个页面这个页面下载用于训练符号检测器的数据集。 对于无人驾驶汽车,图像中将有四个类别用于标记:行人,汽车,摩托车和背景。 当不存在任何后台类时,必须检测到该后台类。 训练深度学习分类模型的一个假设是,至少一个对象将出现在图像中。 通过添加background类,我们克服了这个问题。 神经网络还可以根据标签生成对象的边界框。

YOLO 对象检测算法

最近的对象检测算法是你只需看一次YOLO)。 图像分为多个网格。 图像的每个网格单元都运行相同的算法。 让我们通过定义带有初始化器的层来开始实现:

def pooling_layer(input_layer, pool_size=[2, 2], strides=2, padding='valid'):
    layer = tf.layers.max_pooling2d(
        inputs=input_layer,
  pool_size=pool_size,
  strides=strides,
  padding=padding
    )
    add_variable_summary(layer, 'pooling')
    return layer
def convolution_layer(input_layer, filters, kernel_size=[3, 3], padding='valid',
  activation=tf.nn.leaky_relu):
    layer = tf.layers.conv2d(
        inputs=input_layer,
  filters=filters,
  kernel_size=kernel_size,
  activation=activation,
  padding=padding,
  weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
  weights_regularizer=tf.l2_regularizer(0.0005)
    )
    add_variable_summary(layer, 'convolution')
    return layer
def dense_layer(input_layer, units, activation=tf.nn.leaky_relu):
    layer = tf.layers.dense(
        inputs=input_layer,
  units=units,
  activation=activation,
  weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
  weights_regularizer=tf.l2_regularizer(0.0005)
    )
    add_variable_summary(layer, 'dense')
    return layer

可以注意到,激活层为leaky_relu,权重以截断的正态分布初始化。 这些修改的层可用于构建模型。 该模型如下创建:

yolo = tf.pad(images, np.array([[0, 0], [3, 3], [3, 3], [0, 0]]), name='pad_1')
yolo = convolution_layer(yolo, 64, 7, 2)
yolo = pooling_layer(yolo, [2, 2], 2, 'same')
yolo = convolution_layer(yolo, 192, 3)
yolo = pooling_layer(yolo, 2, 'same')
yolo = convolution_layer(yolo, 128, 1)
yolo = convolution_layer(yolo, 256, 3)
yolo = convolution_layer(yolo, 256, 1)
yolo = convolution_layer(yolo, 512, 3)
yolo = pooling_layer(yolo, 2, 'same')
yolo = convolution_layer(yolo, 256, 1)
yolo = convolution_layer(yolo, 512, 3)
yolo = convolution_layer(yolo, 256, 1)
yolo = convolution_layer(yolo, 512, 3)
yolo = convolution_layer(yolo, 256, 1)
yolo = convolution_layer(yolo, 512, 3)
yolo = convolution_layer(yolo, 256, 1)
yolo = convolution_layer(yolo, 512, 3)
yolo = convolution_layer(yolo, 512, 1)
yolo = convolution_layer(yolo, 1024, 3)
yolo = pooling_layer(yolo, 2)
yolo = convolution_layer(yolo, 512, 1)
yolo = convolution_layer(yolo, 1024, 3)
yolo = convolution_layer(yolo, 512, 1)
yolo = convolution_layer(yolo, 1024, 3)
yolo = convolution_layer(yolo, 1024, 3)
yolo = tf.pad(yolo, np.array([[0, 0], [1, 1], [1, 1], [0, 0]]))
yolo = convolution_layer(yolo, 1024, 3, 2)
yolo = convolution_layer(yolo, 1024, 3)
yolo = convolution_layer(yolo, 1024, 3)
yolo = tf.transpose(yolo, [0, 3, 1, 2])
yolo = tf.layers.flatten(yolo)
yolo = dense_layer(yolo, 512)
yolo = dense_layer(yolo, 4096)
dropout_bool = tf.placeholder(tf.bool)
yolo = tf.layers.dropout(
        inputs=yolo,
  rate=0.4,
  training=dropout_bool
    )
yolo = dense_layer(yolo, output_size, None)

堆叠了几个卷积层,生成了 YOLO 网络。 该网络用于创建用于实时检测的对象检测算法。

总结

在本章中,我们了解了对象定位和检测任务之间的区别。 讨论了几个数据集和评估标准。 讨论了各种解决定位问题和算法的方法,例如用于检测的 R-CNN 和 SSD 模型的变体。 涵盖了在开源存储库中执行检测的过程。 我们使用该技术训练了行人检测模型。 我们还了解了在训练此类模型时需要进行的各种取舍。

在下一章中,我们将学习语义分割算法。 我们将使用该知识来实现医学成像和卫星成像问题的分割算法。

五、语义分割

在本章中,我们将学习各种语义分割技术并为其训练模型。 分割是逐像素分类任务。 解决分割问题的思想是对对象检测问题的扩展。 分割在医学和卫星图像理解等应用中非常有用。

本章将涵盖以下主题:

  • 学习语义分割和实例分割之间的区别
  • 分割数据集和指标
  • 语义分割算法
  • 分割在医学和卫星图像中的应用
  • 实例分割算法

预测像素

图像分类是预测标签或类别的任务。 对象检测是预测几种基于深度学习的算法及其相应边界框的列表的任务。 边界框可能在其中包含除检测到的对象以外的其他对象。 在某些应用中,将每个像素标记到标签很重要,而不是可能包含多个对象的边框。 “语义分割”是预测逐像素标签的任务。

这是图像及其对应的语义分割的示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2khSNZCr-1681567519373)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/ecd4a853-47b0-4b64-959d-e659b7a506a8.jpeg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DPnUSec5-1681567519374)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/f3d07c15-d6fe-4677-9b43-9628b38bc9d4.jpg)]

如图中所示,使用每个像素的标签预测输入图像。 标签可以是天空,树木,人,山和桥。 标签不是分配给整个图像,而是分配给每个像素。 语义分割独立标记像素。 您会注意到每个人都没有区别。 图像中的所有人员均以相同的方式标记。

这是区分相同标签的每个实例的示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GfTycHfZ-1681567519374)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/1c6a1b46-8d59-4882-99a5-cdf1ddfc4ef0.jpg)]

用像素标记分割每个实例的任务称为实例分割。 实例分割可以被认为是具有像素级标签的对象检测的扩展。 语义分段和实例分段的应用非常广泛,下一部分将提供一些应用。

诊断医学图像

可以使用分割技术来诊断医学图像。 现代医学成像技术,例如磁共振成像MRI),计算机断层扫描CT)和视网膜病变创建高质量的图像。 可以将通过这种技术生成的图像划分为多个区域,以检测来自脑部扫描的肿瘤或来自视网膜扫描的斑点。 一些设备提供体积图像,这些图像也可以通过分段进行分析。 分割视频以进行机器人手术,使医生能够在机器人协助的手术中仔细查看区域。 在本章的后面,我们将看到如何分割医学图像。

通过卫星图像了解地球

卫星图像最近变得越来越丰富。 卫星捕获的图像提供了地球整个表面的高分辨率视图。 通过分析卫星图像,我们可以了解有关地球的几件事,例如:

  • 衡量与经济增长相关的国家的架构率
  • 测量油箱
  • 规划和组织交通
  • 计算森林砍伐及其影响
  • 通过对动物进行计数并跟踪其运动来帮助保护野生动植物
  • 发现考古遗址
  • 绘制自然灾害造成的损坏区域

卫星图像还有更多的应用可能。 对于上述大多数问题,解决方案始于卫星图像的分割。 在本章的后面,我们将看到如何分割卫星图像。

使机器人拥有视觉

分割场景对于机器人看清周围世界并与之互动至关重要。 工业和家用机器人必须处理这些对象。 一旦根据对象跨越了机器人的视野,就可以进行处理。 还有更多值得一提的应用:

  • 对缺陷进行分割的工业检查工具
  • 时装行业的色彩诊断; 可以将图像与各种时尚对象进行分割并将其用于颜色解析
  • 区分背景与前景来应用人像效果

在下一部分中,我们将学习一些用于评估分割算法的公共数据集。

数据集

第 4 章,“对象检测”中提到的PASCALCOCO数据集也可以用于分割任务。 标注是不同的,因为它们是按像素标记的。 新算法通常以COCO数据集为基准。 COCO还具有诸如草,墙和天空之类的东西数据集。 像素精度属性可用作评估计法的指标。

除了上面提到的那些以外,在医学影像和卫星影像领域还有其他几个数据集。 这里提供了指向其中一些链接的供您参考:

为分割任务创建训练数据非常昂贵。 有在线工具可用于标注数据集。 麻省理工学院(MIT)提供的 LabelMe 移动应用非常适合标注,可以从这里下载。

语义分割算法

提出了几种基于深度学习的算法来解决图像分割任务。 可以在像素级别应用滑动窗口方法进行分割。 滑动窗口方法会拍摄图像并将图像分成较小的作物。 图像的每种裁剪都被分类为标签。 这种方法昂贵且效率低下,因为它不会重用重叠补丁之间的共享特征。 在以下各节中,我们将讨论一些可以克服此问题的算法。

全卷积网络

全卷积网络FCN)引入了端到端卷积网络的思想。 通过删除全连接层,可以将任何标准的 CNN 架构用于 FCN,其实现在第 4 章,“对象检测”中进行了显示。 全连接层被卷积层代替。 最终层的深度较高,尺寸较小。 因此,可以执行一维卷积以达到所需的标签数量。 但是对于分割,必须保留空间尺寸。 因此,构建完整的卷积网络时没有最大池,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pMaEzKdm-1681567519374)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/3b75d8a1-168a-4625-b727-169ebb0425f4.png)]

该网络的损耗是通过平均每个像素和小批量的交叉熵损耗来计算的。 最后一层的深度等于类数。 FCN 与对象检测相似,只是保留了空间尺寸。 由于某些像素可能会被错误预测,因此该架构产生的输出将很粗糙。 计算量很大,在下一节中,我们将看到如何解决此问题。

SegNet 架构

SegNet 具有编码器和解码器方法。 编码器具有各种卷积层,而解码器具有各种解卷积层。 SegNet 改进了 FCN 产生的粗略输出。 因此,它的内存占用较少。 当特征尺寸减小时,通过反卷积将其再次上采样至图像大小,从而反转了卷积效果。 反卷积学习用于上采样的参数。 由于池层中的信息丢失,这种架构的输出将很粗糙。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A2MvqXve-1681567519374)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/0bca20d8-04c9-48cb-8029-e8af3258c09f.png)]

现在,让我们学习几个新概念,这些概念称为上采样,无规则卷积和转置卷积,它们将帮助我们更好地理解该网络。

通过池化对层进行上采样

在第 1 章“入门”中,我们讨论了最大池化。 最大池化是一种从窗口中选取最大值的采样策略。 对于上采样,可以相反。 每个值都可以用零包围,以对该层进行上采样,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7aGz3skF-1681567519375)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/6c6fa429-432a-4bc4-af17-015e872d5490.png)]

将零添加到与上采样数字相同的位置。 通过记住下采样的位置并将其用于上采样,可以改善反池化,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iRne1NGy-1681567519375)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/7793c888-12eb-40b1-944f-85470767c43c.png)]

从索引角度来看,上采样比附加零产生更好的结果。 这种通过池对层进行上采样的方法是无法学到的,并且可以按原样工作。 接下来,我们将看到如何使用可学习的参数进行上采样和下采样。

通过卷积对层进行采样

可以使用卷积直接对层进行升采样或降采样。 可以增加用于卷积的步幅以引起下采样,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xc87BkKm-1681567519375)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/d2cd8c90-7707-4786-a5bc-e40b08a8a35d.png)]

通过卷积的下采样被称为无孔卷积扩张卷积大卷积。 类似地,可以通过学习内核将其反转为升采样,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1GdfQfrj-1681567519375)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/9e542e78-5c13-4d7f-8d96-e5cedc35bdec.png)]

直接使用卷积的上采样可以称为转置卷积。 其他一些同义词是反卷积分数步卷积上卷积。 现在,了解了升采样的过程。 这是描述先前算法的代码片段:

input_height = 360 input_width = 480 kernel = 3 filter_size = 64 pad = 1 pool_size = 2

输入之后,它遵循大小逐渐减小的通常的卷积神经网络,可以称为编码器。 以下代码可用于定义编码器:

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Layer(input_shape=(3, input_height, input_width)))
# encoder model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(filter_size, kernel, kernel,
  border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(128, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(256, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(512, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))

可以使用以下代码将编码器的输出以增大的尺寸馈入解码器:

# decoder model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(512, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.UpSampling2D(size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(256, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.UpSampling2D(size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(128, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.UpSampling2D(size=(pool_size, pool_size)))
model.add(tf.keras.layers.ZeroPadding2D(padding=(pad, pad)))
model.add(tf.keras.layers.Conv2D(filter_size, kernel, kernel, border_mode='valid'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Conv2D(nClasses, 1, 1, border_mode='valid', ))

解码图像的大小与输入的大小相同,并且可以使用以下代码来训练整个模型:

model.outputHeight = model.output_shape[-2]
model.outputWidth = model.output_shape[-1]
model.add(tf.keras.layers.Reshape((nClasses, model.output_shape[-2] * model.output_shape[-1]),
  input_shape=(nClasses, model.output_shape[-2], model.output_shape[-1])))
model.add(tf.keras.layers.Permute((2, 1)))
model.add(tf.keras.layers.Activation('softmax'))
model.compile(loss="categorical_crossentropy", optimizer=tf.keras.optimizers.Adam, metrics=['accuracy'])

这种对图像进行编码和解码的方式克服了基于 FCN 的模型的缺点。 接下来,我们将看到具有膨胀卷积的不同概念。

用于更好训练的跳跃连接

分割输出的粗糙程度可以通过跳过架构来限制,并且可以获得更高的分辨率。 另一种替代方法是按比例放大最后三层并将其平均,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2T0Dhno-1681567519376)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/1cf06efe-233a-40d0-9fa5-7f53ab8f18dc.png)]

此算法将在后面的部分中用作卫星图像的示例。

膨胀卷积

逐像素分类和图像分类在结构上不同。 因此,减少信息的池化层将产生粗略的分段。 但是请记住,池化对于拥有更广阔的视野并允许采样至关重要。 引入了一种名为扩张卷积的新想法,以解决该问题,从而在进行更广阔视野的同时减少损耗。 扩大的卷积本质上是通过跳过窗口中的每个像素来进行卷积,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Je8hdvQ9-1681567519376)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/1caea247-6635-401e-a844-b023c12f9366.png)]

膨胀距离随层而变化。 这样的分割结果的输出被放大以得到更精细的分辨率。 训练了一个单独的网络以进行多尺度聚合。

DeepLab

Chen 等人提出的 DeepLab 在多个尺度上执行卷积,并使用来自各种尺度的特征获得分数图。 然后对得分图进行插值,并通过条件随机场CRF)进行最终分割。 图像的这种比例处理可以通过使用其自己的 CNN 处理各种大小的图像,或者通过具有不同水平的卷积卷积的并行卷积来执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6MCkWW7u-1681567519376)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/c958122d-5ce1-4d41-89a1-d2203bb2c7f5.png)]

经 Chen 等人许可复制。

RefiNet

膨胀卷积需要更大的输入,因此占用大量内存。 使用高分辨率图片时,这会带来计算问题。 里德等人提出了一种称为 RefiNet 的方法来克服此问题,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NwtrqS3Q-1681567519376)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/db354e6d-4923-4bbc-947a-44c5ba5be7c7.png)]

经 Reid 等人许可复制。

RefiNet 使用编码器,然后使用解码器。 CNN 的编码器输出。 解码器连接各种大小的特征:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3aGdMD7L-1681567519376)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/836b137d-c3de-4c2c-baa2-c6e86dd1b6fc.png)]

经 Reid 等人许可复制。

连接完成后会放大低维特征。

PSPnet

Zhoa 等人介绍的 PSPnet 中使用了全局内容。 方法是增加池化层的内核大小。 池化以金字塔的方式进行。 金字塔同时覆盖图像的各个部分和大小。 架构之间存在损失,因此无法进行适当的监管。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XDRPq2OQ-1681567519377)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/1a1c9433-d75c-4c5d-add8-1a1c9fc9ec8b.png)]

经 Zhao 等人许可复制。

大内核很重要

Peng 等人展示了大内核的重要性。 大内核比小内核具有更大的接受范围。 这些大内核的计算复杂度可用于以较小的内核来克服。 最后有一个边界优化网络。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEsYOtq8-1681567519377)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/3f5d488c-04a0-4396-a2a8-c1fb2bcbf1aa.png)]

经 Peng 等人许可复制。

DeepLab v3

Chen 等人在论文中使用批量归一化以提高表现。 特征的多尺度以级联方式编码,以提高表现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfmnVaqA-1681567519377)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/301dc866-0bfd-4010-a5f1-df4e33e12e34.png)]

经 Chen 等人许可复制。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J2WLqoNV-1681567519377)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/65958e56-9dfc-4075-8de4-d31f9bd2662e.png)]

经 Chen 等人许可复制。

我们已经看到了几种架构可以使用深度学习提高图像分割的准确率。 接下来,我们将看到在医学成像中的应用。

超神经分割

Kaggler 是一个组织进行预测建模和分析竞赛的组织。 Kagglers 曾经受到挑战,要从颈部超声图像中分割神经结构。 可以从这里下载有关该数据的数据。 Ronneberger 等人提出的 UNET 模型类似于自编码器,但具有卷积而不是全连接层。 这里有一个编码部分,其卷积减小,而解码器部分的卷积增大,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c2JGuGJk-1681567519377)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/d5f0233d-03ef-4826-9cba-8a3bbf2f4eb3.png)]

该图说明了 UNET 模型的架构[经 Ronneberger 等人许可复制]

相似大小的编码器和解码器部分的卷积通过跳过连接来学习。 模型的输出是一个介于 0 到 1 之间的掩码。让我们从导入函数开始,借助以下代码:

import os
from skimage.transform import resize
from skimage.io import imsave
import numpy as np
from data import load_train_data, load_test_data

在所有导入之后,我们现在将使用以下代码定义大小:

image_height, image_width = 96, 96 smoothness = 1.0 work_dir = ''

现在我们将定义dice_coefficient及其损失函数。 在这种情况下,dice_coefficient也是度量标准:

def dice_coefficient(y1, y2):
    y1 = tf.flatten(y1)
    y2 = tf.flatten(y2)
    return (2\. * tf.sum(y1 * y2) + smoothness) / (tf.sum(y1) + tf.sum(y2) + smoothness)
def dice_coefficient_loss(y1, y2):
    return -dice_coefficient(y1, y2)

UNET 模型可以定义如下:

def preprocess(imgs):
    imgs_p = np.ndarray((imgs.shape[0], image_height, image_width), dtype=np.uint8)
    for i in range(imgs.shape[0]):
        imgs_p[i] = resize(imgs[i], (image_width, image_height), preserve_range=True)
    imgs_p = imgs_p[..., np.newaxis]
    return imgs_p
def covolution_layer(filters, kernel=(3,3), activation='relu', input_shape=None):
    if input_shape is None:
        return tf.keras.layers.Conv2D(
            filters=filters,
  kernel=kernel,
  activation=activation)
    else:
        return tf.keras.layers.Conv2D(
            filters=filters,
  kernel=kernel,
  activation=activation,
  input_shape=input_shape)
def concatenated_de_convolution_layer(filters):
    return tf.keras.layers.concatenate([
        tf.keras.layers.Conv2DTranspose(
            filters=filters,
  kernel=(2, 2),
  strides=(2, 2),
  padding='same'
  )],
  axis=3
  )

所有层都已连接并使用,如以下代码所示:

unet = tf.keras.models.Sequential()
inputs = tf.keras.layers.Input((image_height, image_width, 1))
input_shape = (image_height, image_width, 1)
unet.add(covolution_layer(32, input_shape=input_shape))
unet.add(covolution_layer(32))
unet.add(pooling_layer())
unet.add(covolution_layer(64))
unet.add(covolution_layer(64))
unet.add(pooling_layer())
unet.add(covolution_layer(128))
unet.add(covolution_layer(128))
unet.add(pooling_layer())
unet.add(covolution_layer(256))
unet.add(covolution_layer(256))
unet.add(pooling_layer())
unet.add(covolution_layer(512))
unet.add(covolution_layer(512))

这些层是连接在一起的,并使用了反卷积层:

unet.add(concatenated_de_convolution_layer(256))
unet.add(covolution_layer(256))
unet.add(covolution_layer(256))
unet.add(concatenated_de_convolution_layer(128))
unet.add(covolution_layer(128))
unet.add(covolution_layer(128))
unet.add(concatenated_de_convolution_layer(64))
unet.add(covolution_layer(64))
unet.add(covolution_layer(64))
unet.add(concatenated_de_convolution_layer(32))
unet.add(covolution_layer(32))
unet.add(covolution_layer(32))
unet.add(covolution_layer(1, kernel=(1, 1), activation='sigmoid'))
unet.compile(optimizer=tf.keras.optimizers.Adam(lr=1e-5),
  loss=dice_coefficient_loss,
  metrics=[dice_coefficient])

接下来,可以通过使用以下代码对模型进行图像训练:

x_train, y_train_mask = load_train_data()
x_train = preprocess(x_train)
y_train_mask = preprocess(y_train_mask)
x_train = x_train.astype('float32')
mean = np.mean(x_train)
std = np.std(x_train)
x_train -= mean
x_train /= std
y_train_mask = y_train_mask.astype('float32')
y_train_mask /= 255.   unet.fit(x_train, y_train_mask, batch_size=32, epochs=20, verbose=1, shuffle=True,
  validation_split=0.2)
x_test, y_test_mask = load_test_data()
x_test = preprocess(x_test)
x_test = x_test.astype('float32')
x_test -= mean
x_test /= std
y_test_pred = unet.predict(x_test, verbose=1)
for image, image_id in zip(y_test_pred, y_test_mask):
    image = (image[:, :, 0] * 255.).astype(np.uint8)
    imsave(os.path.join(work_dir, str(image_id) + '.png'), image)

图像可以进行预处理和使用。 现在可以进行图像的训练和测试了。 训练模型后,分割会产生良好的结果,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dXnekW1M-1681567519378)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/92227668-9c13-4160-b879-f011ded4bb4c.png)]

我们已经训练了可以分割医学图像的模型。 该算法可以在几种用例中使用。 在下一节中,我们将看到如何分割卫星图像。

分割卫星图像

在本节中,我们将使用国际摄影测量与遥感学会ISPRS)提供的数据集。 数据集包含 5 毫米分辨率的德国波茨坦的卫星图像。 这些图像带有红外和图像高度轮廓的附加数据。 与图像相关联的六个标签是:

  • 架构
  • 植被
  • 树木
  • 巢穴
  • 杂物
  • 硬质

总共提供了 8,000 x 6,000 色块的 38 张图像。 请转到页面并填写表格。 之后,在表单上选择以下选项:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RB9IELmY-1681567519378)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/3272ab24-2a2e-4ebe-bf40-91d3fd5d9eb0.png)]

发布表格后,将向您发送电子邮件,从中可以下载数据。

为分割建模 FCN

导入库并获得输入的形状。 标签数定义为6

from .resnet50 import ResNet50
nb_labels = 6   img_height, img_width, _ = input_shape
input_tensor = tf.keras.layers.Input(shape=input_shape)
weights = 'imagenet'

在 ImageNet 上预先训练的ResNet模型将用作基本模型。 以下代码可用于使用ResNet定义基本模型:

resnet50_model = ResNet50(
    include_top=False, weights='imagenet', input_tensor=input_tensor)

现在,我们将使用以下代码从ResNet中获取最后三层:

final_32 = resnet50_model.get_layer('final_32').output
final_16 = resnet50_model.get_layer('final_16').output
final_x8 = resnet50_model.get_layer('final_x8').output

必须压缩每个跳过连接以匹配等于标签数的通道:

c32 = tf.keras.layers.Conv2D(nb_labels, (1, 1))(final_32)
c16 = tf.keras.layers.Conv2D(nb_labels, (1, 1))(final_16)
c8 = tf.keras.layers.Conv2D(nb_labels, (1, 1))(final_x8)

可以使用双线性插值来调整压缩跳过连接的输出大小。 可以通过使用可以计算 TensorFlow 操作的Lambda层来实现插值。 以下代码段可用于使用 lambda 层进行插值:

def resize_bilinear(images):
    return tf.image.resize_bilinear(images, [img_height, img_width])
r32 = tf.keras.layers.Lambda(resize_bilinear)(c32)
r16 = tf.keras.layers.Lambda(resize_bilinear)(c16)
r8 = tf.keras.layers.Lambda(resize_bilinear)(c8)

使用以下代码,可以通过添加三个值来合并我们定义的三层:

m = tf.keras.layers.Add()([r32, r16, r8])

可以使用 softmax 激活来应用模型的概率。 在应用 softmax 之前和之后调整模型大小:

x = tf.keras.ayers.Reshape((img_height * img_width, nb_labels))(m)
x = tf.keras.layers.Activation('img_height')(x)
x = tf.keras.layers.Reshape((img_height, img_width, nb_labels))(x)
fcn_model = tf.keras.models.Model(input=input_tensor, output=x)

已经定义了一个简单的 FCN 层,经过训练后,它会产生以下结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YRRmh8Jt-1681567519378)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/c09f3fc7-b5d0-4eb1-9b22-e68707be3f96.png)]

您会看到六个标签的预测是合理的。 接下来,我们将学习分割实例。

分割实例

在分析图像时,我们的兴趣只会吸引到图像中的某些实例。 因此,它不得不从图像的其余部分中分割这些实例。 从其余信息中分离所需信息的过程被广泛称为分割实例。 在此过程中,首先拍摄输入图像,然后将边界框与对象一起定位,最后,将为每个类别预测逐像素掩码。 对于每个对象,都将计算像素级精度。 有几种用于分割实例的算法。 最近的算法之一是 He 等人提出的 Mask RCNN 算法。 下图描绘了 Mask R-CNN 的架构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FRmnkb8X-1681567519378)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/608bc4e7-8b4b-46b9-98d9-1626226bc859.png)]

经 He 等人许可复制。

该架构看起来与 R-CNN 类似,但增加了分段。 这是一个具有端到端训练的多阶段网络。 学习了区域提案。 该网络分为两个部分,一个用于检测,另一个用于分类评分。 结果非常好,如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqEcEyx1-1681567519379)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-cv/img/a0697d7c-9d03-46fd-9ae2-ff00ff587825.png)]

该图说明了分割实例的过程,请注意,准确地检测了对象并进行了相应的分割。

同一网络还可以预测人的姿势。 分割和检测这两个任务是并行处理的。

总结

在本章中,我们学习了各种分割算法。 我们还看到了用于基准测试的数据集和指标。 我们将学到的技术应用于卫星和医学图像的分割。 最后,我们谈到了 Mask R-CNN 算法的实例分割。

在下一章中,我们将学习相似性学习。 相似性学习模型学习两个图像之间的比较机制。 对于人脸识别等多种应用很有用。 我们将学习几种可用于相似性学习的模型架构。

相关文章
|
3月前
|
机器学习/深度学习 监控 算法
车辆违停检测:基于计算机视觉与深度学习的自动化解决方案
随着智能交通技术的发展,传统人工交通执法方式已难以满足现代城市需求,尤其是在违法停车监控与处罚方面。本文介绍了一种基于计算机视觉和深度学习的车辆违停检测系统,该系统能自动监测、识别并报警违法停车行为,大幅提高交通管理效率,降低人力成本。通过使用YOLO算法进行车辆检测,结合区域分析判断车辆是否处于禁停区,实现了从车辆识别到违停判定的全流程自动化。此系统不仅提升了交通管理的智能化水平,也为维护城市交通秩序提供了技术支持。
|
3月前
|
机器学习/深度学习 人工智能 算法
深度学习在计算机视觉中的突破与未来趋势###
【10月更文挑战第21天】 近年来,深度学习技术极大地推动了计算机视觉领域的发展。本文将探讨深度学习在图像识别、目标检测和图像生成等方面的最新进展,分析其背后的关键技术和算法,并展望未来的发展趋势和应用前景。通过这些探讨,希望能够为相关领域的研究者和从业者提供有价值的参考。 ###
170 4
|
3月前
|
机器学习/深度学习 人工智能 TensorFlow
探索深度学习与计算机视觉的融合:构建高效图像识别系统
探索深度学习与计算机视觉的融合:构建高效图像识别系统
81 0
|
3月前
|
机器学习/深度学习 传感器 算法
行人闯红灯检测:基于计算机视觉与深度学习的智能交通解决方案
随着智能交通系统的发展,传统的人工交通违法判断已难以满足需求。本文介绍了一种基于计算机视觉与深度学习的行人闯红灯自动检测系统,涵盖信号灯状态检测、行人检测与跟踪、行为分析及违规判定与报警四大模块,旨在提升交通管理效率与安全性。
|
3月前
|
机器学习/深度学习 计算机视觉
深度学习与计算机视觉的最新进展
深度学习与计算机视觉的最新进展
|
5月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习与计算机视觉的结合:技术趋势与应用
深度学习与计算机视觉的结合:技术趋势与应用
292 9
|
6月前
|
机器学习/深度学习 人工智能 自动驾驶
震撼发布!深度学习如何重塑计算机视觉:一场即将改变世界的革命!
【8月更文挑战第6天】随着AI技术的发展,深度学习已成为计算机视觉的核心驱动力。卷积神经网络(CNN)能自动提取图像特征,显著提升识别精度。目标检测技术如YOLO和Faster R-CNN实现了快速精准检测。语义分割利用FCN和U-Net达到像素级分类。这些进展极大提升了图像处理的速度与准确性,为自动驾驶、医疗影像等领域提供了关键技术支撑,预示着计算机视觉更加光明的未来。
59 0
|
7月前
|
机器学习/深度学习 人工智能 自然语言处理
计算机视觉借助深度学习实现了革命性进步,从图像分类到复杂场景理解,深度学习模型如CNN、RNN重塑了领域边界。
【7月更文挑战第2天】计算机视觉借助深度学习实现了革命性进步,从图像分类到复杂场景理解,深度学习模型如CNN、RNN重塑了领域边界。AlexNet开启新时代,后续模型不断优化,推动对象检测、语义分割、图像生成等领域发展。尽管面临数据隐私、模型解释性等挑战,深度学习已广泛应用于安防、医疗、零售和农业,预示着更智能、高效的未来,同时也强调了技术创新、伦理考量的重要性。
88 1
|
7月前
|
机器学习/深度学习 人工智能 固态存储
深度学习在计算机视觉中的应用:重塑视觉感知的未来
【7月更文挑战第1天】深度学习重塑计算机视觉未来:本文探讨了深度学习如何革新CV领域,核心涉及CNN、RNN和自注意力机制。应用包括目标检测(YOLO、SSD等)、图像分类(VGG、ResNet等)、人脸识别及医学影像分析。未来趋势包括多模态融合、语义理解、强化学习和模型可解释性,推动CV向更高智能和可靠性发展。
|
8月前
|
机器学习/深度学习 搜索推荐 自动驾驶
深度学习与计算机视觉的融合发展
深度学习与计算机视觉的融合发展
67 1