语义分割与边缘提取

节列表 ↓

本章阐述了如何基于深度学习实现语义分割,涵盖训练阶段与推理阶段的具体应用。

通过 semantic segmentation语义分割,我们利用深度学习(DL)网络将输入图像的每个像素分配到一个类别。

image/svg+xml apple lemon orange background
语义分割的一个可能示例:输入图像的每个像素都被分配到一个类别,但该类别中三个不同的 “apple”苹果实例和两个不同的 “orange”橙子实例均不构成独立对象。

语义分割的结果是一个输出图像,其中像素值表示输入图像中对应像素被分配的类别。因此,在 HALCON 中,输出图像的尺寸与输入图像相同。对于一般的深度学习网络,表示更复杂特征的深层特征图通常比输入图像尺寸更小(参见 深度学习 中“网络与训练过程”一节)。为获得与输入相同尺寸的输出,HALCON 采用包含两个组件的分割网络:编码器和解码器。编码器确定输入图像的特征,例如用于基于深度学习的分类。由于这些信息以压缩格式“编码”存储,需要解码器将其还原为预期结果——本例中即为将每个像素分配至特定类别。需注意的是,在像素分类过程中,同一类别的重叠实例不会被识别为独立个体。

边缘检测 是语义分割的特殊情况,模型被训练用于区分两个类别:“edge”和“background”。更多信息请参阅 “解决方案指南 I - 基础篇”

image/svg+xml edges background
边缘检测的一个可能示例:作为语义分割的特殊情况,其中输入图像的每个像素都被分配到两个类别之一:“edge”和“background”。

基于深度学习的语义分割功能已集成于 HALCON 更通用的深度学习模型中。有关该模型的详细信息,请参阅 深度学习 / 模型 一章。应用深度学习所需的具体系统要求,请参阅 HALCON “安装指南”

以下各节将介绍语义分割所需的一般工作流程、相关数据与参数信息,以及评估指标的说明。

一般工作流程

本节描述基于深度学习的语义分割任务的一般工作流程。该流程分为四个部分:数据预处理、模型训练、训练模型评估以及新图像推理。在此我们假设您的数据集已完成标注,详见下文“数据”部分。可参考 HDevelop 示例系列 segment_pill_defects_deep_learning 了解应用实例。示例 segment_edges_deep_learning_with_retraining 则完整展示了边缘提取应用的工作流程。

预处理数据

本部分介绍如何对数据进行预处理。具体步骤也可在 HDevelop 示例 segment_pill_defects_deep_learning_1_preprocess.hdev 中查看。

  1. 需要传输的是训练数据集中哪些图像所包含的信息。该操作通过以下函数实现:

    • read_dl_dataset_segmentation

    由此创建了一个名为 DLDataset 的字典,它作为数据库存储了关于数据的所有必要信息。有关数据及其传输方式的更多信息,请参阅下文的“数据”部分以及 深度学习 / 模型 一章。

  2. 将字典 DLDataset 表示的数据集进行拆分。可通过以下函数实现:

    • split_dl_dataset

    生成的分割结果将通过键 split 保存至 DLDataset 中每个样本条目中。

  3. 现在您可以对数据集进行预处理。为此,您可以使用以下函数:

    • preprocess_dl_dataset

    本函数还提供了如何实施定制化预处理函数的指导。

    要使用此函数,需指定预处理参数,例如图像尺寸。对于后者,应选择能清晰识别待分割区域的最小图像尺寸。将所有参数及其值存储在字典 DLPreprocessParam中,为此可使用以下函数:

    • create_dl_preprocess_param

    我们建议保存此字典 DLPreprocessParam,以便在后续推理阶段能够访问预处理参数值。

    在数据集预处理过程中,preprocess_dl_dataset 还会为训练数据集生成权重图像 weight_image。该图像为每个类别分配其在训练过程中像素获得的权重(“class weights”),具体详见下文“模型参数与超参数”一节。

模型训练

本部分介绍如何训练深度学习语义分割模型。具体步骤也可在 HDevelop 示例 segment_pill_defects_deep_learning_2_train.hdev 中查看。

  1. 必须读取网络使用算子

  2. 模型参数需要进行设置通过算子

    此类参数例如 'image_dimensions'"image_dimensions""image_dimensions""image_dimensions""image_dimensions""image_dimensions"'class_ids'"class_ids""class_ids""class_ids""class_ids""class_ids",详见 get_dl_model_paramget_dl_model_paramGetDlModelParamGetDlModelParamGetDlModelParamget_dl_model_param 文档。

    您可随时获取当前参数值使用算子

  3. 设置训练参数并将其存储在字典 TrainParam 中。这些参数包括:

    • 超参数,概述请参见下文“模型参数与超参数”一节及 深度学习 一章。

    • 用于可能的数据增强的参数(可选)。

    • 用于训练期间评估的参数。

    • 用于训练结果可视化的参数。

    • 用于序列化的参数。

    可通过以下函数实现

    • create_dl_train_param

  4. 训练模型。可以通过以下函数实现

    • train_dl_model

    该函数需要:

    • 模型句柄 DLModelHandleDLModelHandleDLModelHandleDLModelHandleDLModelHandledlmodel_handle

    • 包含数据信息的字典 DLDataset

    • 包含训练参数的字典 'TrainParam'"TrainParam""TrainParam""TrainParam""TrainParam""TrainParam"

    • 训练应运行的 epochs(周期) 次数信息。

    若使用 train_dl_model 函数,则会可视化总损失值及可选的评估指标。

训练模型评估

本部分对语义分割模型进行评估。具体步骤亦可在 HDevelop 示例 segment_pill_defects_deep_learning_3_evaluate.hdev 中查看。

  1. 设置可能影响评估的模型参数,例如 'batch_size'"batch_size""batch_size""batch_size""batch_size""batch_size",使用算子

  2. 该评估可通过以下函数便捷完成

    • evaluate_dl_model

  3. 字典 EvaluationResult 存储了请求的评估指标。您可以可视化评估结果使用函数

    • dev_display_segmentation_evaluation

新图像推理

本部分涵盖深度学习语义分割模型的应用。具体步骤亦可在 HDevelop 示例 segment_pill_defects_deep_learning_4_infer.hdev 中查看。

  1. 设置参数,例如 'batch_size'"batch_size""batch_size""batch_size""batch_size""batch_size" 使用算子

  2. 为每张图像生成一个数据字典 DLSample。这可通过以下函数实现

    • gen_dl_samples_from_images

  3. 对图像进行预处理,如同训练时所做的那样。我们建议使用以下函数进行操作

    • preprocess_dl_samples

    在预处理步骤中保存字典 DLPreprocessParam 后,可直接将其作为输入来指定所有参数值。

  4. 应用模型使用算子

  5. 从字典 'DLResultBatch'"DLResultBatch""DLResultBatch""DLResultBatch""DLResultBatch""DLResultBatch" 中检索结果。可通过对分割图像应用算子 thresholdthresholdThresholdThresholdThresholdthreshold,选取特定类别的区域。

数据

我们将用于训练和评估的数据与用于推理的数据区分开来。后者仅包含原始图像,前者则包含带有信息标注和真值标注的图像。您需要为每个像素提供信息,定义其所属类别(通过 segmentation_image 实现,具体说明见下文)。

作为基本概念,该模型通过字典处理数据,即它接收输入数据时采用字典 DLSample,并分别返回字典 DLResultDLTrainResult。有关数据处理的更多信息,请参阅 深度学习 / 模型

训练和评估数据

训练数据用于针对特定任务训练网络。该数据集包含图像及其对应信息,需以模型可处理的形式提供。关于图像要求,请参阅下文“图像”部分的详细说明。图像及其真值标注信息通过字典 DLDataset 提供,每个样本均配有对应的 segmentation_image,该图像为每个像素定义了类别。

Classes

不同类别是网络区分出的集合或分类。它们被设置在字典 DLDataset 中,并通过算子 set_dl_model_paramset_dl_model_paramSetDlModelParamSetDlModelParamSetDlModelParamset_dl_model_param 传递给模型。

语义分割 中,我们特别提醒您注意两种特殊情况:“background”类别以及声明为“ignore”的类别:

  • 'background' 背景类别: 网络将背景类别视为普通类别处理。设置背景类别并非必需。但若数据集中存在某些您不关注的类别(尽管网络仍需学习这些类别),可将其统一标记为“background”。此举将使背景类别的多样性得到提升。更多信息请参阅函数 preprocess_dl_samples

  • 'ignore' 忽略类别: 可以将一个或多个类别标记为“ignore”。分配到“ignore”类别的像素将被损失函数忽略,同时在所有度量和评估中也被忽略。有关损失函数的更多信息,请参阅 深度学习 一章中的“网络与训练过程”一节。 网络不会将任何像素分类到标记为“ignore”的类别中。此外,标记为该类别的像素将与其他像素相同,被网络归类至非“ignore”类别。如下图所示示例,这意味着网络将同时处理“border”类别的像素,但不会将任何像素归类至“border”类别。可通过 set_dl_model_paramset_dl_model_paramSetDlModelParamSetDlModelParamSetDlModelParamset_dl_model_param 参数 'ignore_class_ids'"ignore_class_ids""ignore_class_ids""ignore_class_ids""ignore_class_ids""ignore_class_ids" 声明类别为“ignore”。

边缘提取 中仅区分两类:“border”边界与“background”背景。“border”类与普通类标注方式相同。因此仅标注一类,该类称为“border”。

DLDataset

本词典作为数据库使用,即存储网络所需的所有数据信息,例如图像名称与路径、类别等。通用概念及关键条目请参阅 深度学习 / 模型 文档。仅适用于语义分割的键涉及 segmentation_image(参见下方条目)。通过 segmentation_dirsegmentation_file_name 键,您可指定图像的命名规则及存储位置。

segmentation_image

为了使网络能够学习不同类别成员的外观特征,你需要为训练数据集中每张图像的每个像素标注其所属类别。具体实现方式是:对于输入图像中的每个像素点,将其对应的分类信息以像素值的形式存储在相应的 segmentation_image 中。这些标注即为真实标注。

image/svg+xml image/svg+xml
( 1) ( 2)
segmentation_image 示意图。为便于可视化,采用灰度值表示数字。 (1) 输入图像。 (2) 对应的 segmentation_image 提供类别标注, 0:background(白色),1:orange,2:lemon,3:apple,4: border(黑色)作为独立类别以便声明为“ignore”。

您需要足够的训练数据将其划分为三个子集:一个用于训练,一个用于验证,一个用于测试神经网络。这些子集最好是独立且同分布的(参见 深度学习 一章中的“数据”一节)。划分时可使用 split_dl_data_set 函数。

图像

无论应用场景如何,网络对图像均有尺寸、灰度值范围及类型等要求。具体数值取决于网络本身,不同网络的具体参数请参阅 read_dl_modelread_dl_modelReadDlModelReadDlModelReadDlModelread_dl_model 文档。对于已加载的网络,可通过 get_dl_model_paramget_dl_model_paramGetDlModelParamGetDlModelParamGetDlModelParamget_dl_model_param 查询参数。为满足这些要求,您可能需要对图像进行预处理。对整个样本(包括图像)的标准预处理已在 preprocess_dl_samples 中实现,本函数还提供了如何实现自定义预处理函数的指导。

网络输出

网络输出取决于任务:

训练

作为输出,该算子将返回一个名为 DLTrainResultDLTrainResultDLTrainResultDLTrainResultDLTrainResultdltrain_result 的字典,其中包含总损失的当前值以及模型中所有其他损失的值。

推理与评估

作为输出,网络将为每个样本返回一个名为 DLResultDLResultDLResultDLResultDLResultdlresult 的字典。对于语义分割任务,该字典将为每张输入图像包含以下两张图像的句柄:

  • segmentation_image:一张图像,其中每个像素的值对应于其所属像素被分配到的类别(见下图)。

  • segmentation_confidence:一张图像,其中每个像素都包含该像素在输入图像中分类结果的置信度值(见下图)。

image/svg+xml image/svg+xml
( 1) ( 2)
不同数据图像的示意图。为便于观察,采用灰度值表示数值。(1) segmentation_image:即使声明为“ignore”的类别的像素(见上图)也会被分类。(2) segmentation_confidence

模型参数与超参数

除了 深度学习 中介绍的通用 DL 超参数外,还存在另一个与语义分割相关的超参数:

对于语义分割模型,模型参数以及超参数(除“class weights”外)均通过 set_dl_model_paramset_dl_model_paramSetDlModelParamSetDlModelParamSetDlModelParamset_dl_model_param 进行设置。模型参数的详细说明请参见 get_dl_model_paramget_dl_model_paramGetDlModelParamGetDlModelParamGetDlModelParamget_dl_model_param

请注意,由于内存占用较大,通常只能进行小批量训练。因此训练速度较慢,建议使用高于分类任务的动量参数。HDevelop 示例文件 segment_pill_defects_deep_learning_2_train.hdev 为 HALCON中 分割网络的训练提供了良好的初始参数值。

'class weights'

通过超参数“class weights”,您可以在训练过程中为每个类别分配其像素的权重。通过为不同类别赋予不同权重,可强制网络以不同重要性学习各类别。这在某些场景下尤为有用,例如缺陷检测——当某类缺陷在图像中仅占极小比例时,若该缺陷类别在图像中占据主导地位。在此类场景中,若网络将所有像素均判定为背景(即“非缺陷”),通常能获得较好的损失值。为不同类别分配差异化权重有助于重新平衡分布。简言之,您可通过调整损失值,使训练重点集中在您认定的关键像素上。

网络通过 weight_image 获取这些权重,该图像为每个训练样本创建。在 weight_image 中,每个像素值对应输入图像在训练过程中对应像素获得的权重。可通过以下两种方法创建这些图像:

  • calculate_dl_segmentation_class_weights 可帮助您创建类权重。该函数采用逆类频率权重概念。

  • gen_dl_segmentation_weight_images 使用类权重生成 weight_image

此步骤必须在训练前完成。通常在预处理阶段进行,属于预处理函数 preprocess_dl_dataset 的一部分。请注意,该超参数在函数中被称为 class_weightsClassWeightsClassWeightsClassWeightsClassWeightsclassWeightsclass_weights。下图展示了不同权重设置下图像的呈现效果。

请注意,当将图像的特定区域权重设为 0.0 时,这些像素不会对损失值产生影响(有关损失值的更多信息,请参阅 深度学习 中“网络及其训练”一节)。

image/svg+xml image/svg+xml
( 1) ( 2)
weight_image 的示意图。为便于可视化,采用灰度值表示数值。(1) segmentation_image 定义图像中每个像素的类别:0:background(白色),1:orange,2:lemon,3:apple,4:border(黑色),该类别被声明为“ignore”。(2) 对应 weight_image 提供类权重,background:1.0,orange:30.0,lemon:75.0。声明为“ignore”的类别像素(此处为边界类)将被忽略并赋予权重 0.0。

语义分割数据的评估指标

对于语义分割,HALCON支持以下评估指标。请注意,计算图像的此类指标时需要相关的真值信息。下文所述的所有单张图像评估指标( mean_iou)均可扩展至任意数量的图像集。具体实现方式是将所有输出图像组合成一张大型图像,以此为基础进行指标计算。需注意:计算过程中将忽略所有标记为“ignore”类别的像素。

pixel_accuracy

像素精度即所有被正确预测类别标签的像素与总像素数量之比。

image/svg+xml image/svg+xml image/svg+xml pixel accuracy =
( 1) ( 2) ( 3)
pixel_accuracy 的可视化示例:(1) segmentation_image 定义每个像素的真实类别(参见上文“数据”部分)。声明为“ignore”类别的像素以黑色标注。(2) 输出图像中,声明为“ignore”类别的像素同样被分类。(3) 像素精度即橙色区域总面积之比。注:标记为“ignore”类别的像素将被忽略。
class_pixel_accuracy

每类像素准确率仅考虑单个类别的像素。其定义为正确预测像素数与该类别标注像素总数之比。

若某类未出现,则其 class_pixel_accuracy 值设为 -1 且不计入平均值 mean_accuracy 的计算。

mean_accuracy

平均准确率定义为所有出现类别的类像素准确率(class_pixel_accuracy)的平均值。

class_iou

特定类别的交并比(intersection over union,IoU)表示正确预测像素与标注像素和预测像素并集之比。从视觉上理解,即为区域交集面积与区域并集面积之比,详见下图。

若某类未出现,则其 class_iou 值设为 -1 且不计入 mean_iou 的计算。

image/svg+xml image/svg+xml image/svg+xml IoU=
( 1) ( 2) ( 3)
每类交并比 class_iou 的可视化示例,此处仅展示苹果类别的结果。(1) segmentation_image 定义了每个像素的真实类别(参见“数据”章节)。标记为“ignore”的类别像素以黑色显示。(2) 输出图像,其中标记为“ignore”的类别像素同样被分类。 (3) 交并比值即为苹果类像素区域的交集面积与并集面积之比。需注意:标记为“ignore”类别的像素将被排除计算。
mean_iou

平均交并比定义为所有出现类别的每类交并比(class_iou)的平均值。需注意,每个出现类别对该指标的影响均等,与其所含像素数量无关。

frequency_weighted_iou

至于平均交并比,首先计算每类交并比。但每个出现类别对该指标的贡献会根据其所属像素比例进行加权。需注意像素较多的类别可能主导该指标。

pixel_confusion_matrix

混淆矩阵的概念在 深度学习 一章的“监督训练”一节中进行了阐述。该概念适用于语义分割任务,其中实例为单个像素。


节列表