文章目录
- [1. 简介](#1. 简介)
-
- [1.1 什么是分类](#1.1 什么是分类)
- [1.2 分类的应用场景](#1.2 分类的应用场景)
- [1.3 HALCON 分类器概览](#1.3 HALCON 分类器概览)
- [2. 快速上手:一个完整例程](#2. 快速上手:一个完整例程)
-
- [2.1 第一步:创建分类器](#2.1 第一步:创建分类器)
- [2.2 第二步:添加训练样本](#2.2 第二步:添加训练样本)
- [2.3 第三步:训练分类器](#2.3 第三步:训练分类器)
- [2.4 第四步:分类新物体](#2.4 第四步:分类新物体)
- [2.5 第五步:释放资源](#2.5 第五步:释放资源)
- [3. 理论背景](#3. 理论背景)
-
- [3.1 分类的基本概念](#3.1 分类的基本概念)
-
- [3.1.1 特征与特征空间](#3.1.1 特征与特征空间)
- [3.1.2 线性与非线性分类器](#3.1.2 线性与非线性分类器)
- [3.2 Euclidean与Hyperbox 分类器](#3.2 Euclidean与Hyperbox 分类器)
-
- [3.2.1 Euclidean 分类器(最小距离分类器)](#3.2.1 Euclidean 分类器(最小距离分类器))
- [3.2.2 Hyperbox 分类器](#3.2.2 Hyperbox 分类器)
- [3.3 多层感知器(MLP)](#3.3 多层感知器(MLP))
- [3.4 支持向量机(SVM)](#3.4 支持向量机(SVM))
-
- [3.4.1 从线性到非线性](#3.4.1 从线性到非线性)
- [3.4.2 支持向量与最大间隔](#3.4.2 支持向量与最大间隔)
- [3.4.3 分类公式](#3.4.3 分类公式)
- [3.4.4 核函数类型](#3.4.4 核函数类型)
- [3.4.5 Multi-class扩展策略](#3.4.5 Multi-class扩展策略)
- [3.4.6 SVM的核心优势](#3.4.6 SVM的核心优势)
- [3.5 高斯混合模型(GMM)](#3.5 高斯混合模型(GMM))
- [3.6 K近邻分类器(k-NN)](#3.6 K近邻分类器(k-NN))
- [3.7 卷积神经网络(CNN)](#3.7 卷积神经网络(CNN))
- [4. 如何选择:关键决策指南](#4. 如何选择:关键决策指南)
- [4.1 选择分类方法](#4.1 选择分类方法)
- [4.2 选择合适的特征](#4.2 选择合适的特征)
- [4.3 选择训练样本](#4.3 选择训练样本)
- [5. 实战:一般分类工作流](#5. 实战:一般分类工作流)
-
- [5.1 一般方法](#5.1 一般方法)
-
- [5.1.1 **卤素灯质量检测示例**(分类为好/坏/无):](#5.1.1 卤素灯质量检测示例(分类为好/坏/无):)
- [5.1.2 **创建SVM分类器:**](#5.1.2 创建SVM分类器:)
- [5.1.3 **添加训练样本:**](#5.1.3 添加训练样本:)
- [5.1.4 **特征计算:**](#5.1.4 特征计算:)
- [5.1.5 **训练:**](#5.1.5 训练:)
- [5.1.6 **分类新物体:**](#5.1.6 分类新物体:)
- [5.1.7 **释放内存:**](#5.1.7 释放内存:)
- [5.1.8 **离线/在线分离:**](#5.1.8 离线/在线分离:)
- [5.2 算子概览](#5.2 算子概览)
-
- 5.2.1基本步骤
- [5.2.2 高级操作](#5.2.2 高级操作)
- [5.3 SVM参数调优详解](#5.3 SVM参数调优详解)
-
- [5.3.1 核心参数](#5.3.1 核心参数)
- [5.3.2 速度优化参数](#5.3.2 速度优化参数)
- [5.3.3 其他参数](#5.3.3 其他参数)
- [5.4 Parameter Setting for SVM](#5.4 Parameter Setting for SVM)
-
- [5.4.1 调整 `create_class_svm`](#5.4.1 调整
create_class_svm) - [5.4.2 调整 `add_sample_class_svm`](#5.4.2 调整
add_sample_class_svm) - [5.4.3 调整 `train_class_svm`](#5.4.3 调整
train_class_svm) - [5.4.4 Adjusting `reduce_class_svm`](#5.4.4 Adjusting
reduce_class_svm) - [5.4.5 Adjusting `classify_class_svm`](#5.4.5 Adjusting
classify_class_svm) - [5.4.6 Adjusting `clear_class_svm`](#5.4.6 Adjusting
clear_class_svm)
- [5.4.1 调整 `create_class_svm`](#5.4.1 调整
- 6.SVM算子API参考
-
- `add_class_train_data_svm`
- `add_sample_class_svm`
- `classify_class_svm`
- `clear_class_svm`
- `clear_samples_class_svm`
- `create_class_svm`
- `evaluate_class_svm`
- `get_class_train_data_svm`
- `get_params_class_svm`
- `get_prep_info_class_svm`
- `get_sample_class_svm`
- `get_sample_num_class_svm`
- `get_support_vector_class_svm`
- `get_support_vector_num_class_svm`
- `read_class_svm`
- `read_samples_class_svm`
- `reduce_class_svm`
- `select_feature_set_svm`
- `train_class_svm`
- `write_class_svm`
- `write_samples_class_svm`
1. 简介
1.1 什么是分类
分类就是将一个物体分配为几个预定义类别之一。
当处理图像时,物体通常是像素或者区域。物体通过特征描述,包含,例如:
- 像素物体的颜色 或纹理
- 区域物体的尺寸 或形状特征
将物体分配为一个指定的类,各个类的边界需要已知。这通常情况下通过已知类的取样物体的特征的训练创建。之后,当分类一个未知物体时,被用于训练的特征值和未知物体特征值之间具有最大相关的类被返回。
分类的核心流程:
- 训练阶段:收集已知类别的样本,提取特征,让分类器学习各类别之间的边界
- 预测阶段:对未知物体提取相同的特征,分类器根据学到的规则给出类别
1.2 分类的应用场景
- 分类可用在物体具有相似且在未知变换范围内的情况下。如果你寻找具有某一固定形状的物体,且发现的轮廓周围的点不偏离一个小的给定的距离,模版匹配将更加快速且容易执行。
- 但是如果物体的形状相似,但你不能准确定义这些物体的相似之处,你可以使用分类器。
分类可用于大量不同的任务:
| 应用 | 说明 |
|---|---|
| 图像分割 | 将图像分成颜色或纹理相似的区域 |
| 物体识别 | 从混合物体中找出特定类型 |
| 质量控制 | 判断产品是合格还是不合格 |
| 异常检测 | 发现物体的缺陷或变化 |
| 光学字符识别(OCR) | 识别文字和数字 |
1.3 HALCON 分类器概览
HALCON提供了多种分类器,各有特点:
| 分类器 | 核心思想 | 训练速度 | 分类速度 | 内存占用 | 适用场景 |
|---|---|---|---|---|---|
| MLP | 多层神经网络 | 慢 | 快 | 中 | 通用分类,允许较长训练时间 |
| SVM | 最大间隔超平面 | 较快 | 较慢 | 较大 | 追求高精度,样本量适中 |
| GMM | 高斯概率模型 | 快 | 快 | 低 | 缺陷检测,低维特征 |
| k-NN | 投票表决 | 极快 | 慢 | 大 | 特征探索,需灵活扩展 |
| CNN | 深度卷积网络 | 极慢 | 快 | 极大 | OCR,复杂图像分类 |
此外,还有用于图像分割的简单快速方法Euclidean 分类器 ,Hyperbox分类器 、以及基于 2D 直方图 的分割。
OCR 建议:优先尝试HALCON预训练字体 Universal(基于CNN),再考虑其他方法。
2. 快速上手:一个完整例程
本节通过一个完整的例子演示分类的工作流程:基于形状特征对金属部件(螺母、垫圈、卡环)进行分类。
2.1 第一步:创建分类器
Halcon学习之超盒分类使用 create_class_mlp创建一个 MLP分类器:
halcon
create_class_mlp (6, 5, 3, 'softmax', 'normalization', 3, 42, MLPHandle)
6--- 输入特征维度5--- 隐藏层神经元数3--- 输出类别数'softmax'--- 输出层激活函数'normalization'--- 特征预处理方式42--- 随机种子
返回的 MLPHandle 将在后续所有步骤中使用。
2.2 第二步:添加训练样本
训练图像包含已知类的物体。图像类的指数存储在数组 Classes 中(9 个可用图像),每类 3 张:
halcon
* 图像文件名和对应的类别 ID
FileNames := ['nuts_01','nuts_02','nuts_03', \
'washers_01','washers_02','washers_03', \
'retainers_01','retainers_02','retainers_03']
Classes := [0, 0, 0, 1, 1, 1, 2, 2, 2]
- 开始三个图像中的物体属于类 0
- 接下来的三个图像中的物体属于类 1
- 最后三个图像中包含类 2 的物体

对每张图像进行分割 和特征提取:
halcon
for J := 0 to |FileNames| - 1 by 1
read_image (Image, 'rings/' + FileNames[J])
segment (Image, Objects)
add_samples (Objects, MLPHandle, Classes[J])
endfor
分割过程 --- 使用简单的 blob 分析分割并分开包含在图像中的物体:
halcon
procedure segment (Image, Regions)
binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)
connection (Region, ConnectedRegions)
fill_up (ConnectedRegions, Regions)
return ()
特征提取 --- 对于每一个区域,使用 get_features 确定一个特征向量:
halcon
procedure get_features (Region, Features)
select_obj (Region, SingleRegion, 1)
circularity (SingleRegion, Circularity) * 圆度
roundness (SingleRegion, Distance, Sigma, Roundness, Sides) * 轮廓圆度
moments_region_central_invar (SingleRegion, PSI1, PSI2, PSI3, PSI4) * 4个不变矩
Features := [Circularity, Roundness, PSI1, PSI2, PSI3, PSI4]
return ()
提取的特征:circularity、roundness、以及区域的 4 个矩 moments_region_central_invar。
添加样本 --- 将特征向量和类别 ID 配对添加到分类器:
halcon
procedure add_samples (Regions, MLPHandle, Class)
count_obj (Regions, Number)
for J := 1 to Number by 1
select_obj (Regions, Region, J)
get_features (Region, Features)
add_sample_class_mlp (MLPHandle, Features, Class)
endfor
return ()
2.3 第三步:训练分类器
halcon
train_class_mlp (MLPHandle, 200, 1, 0.01, Error, ErrorLog)
clear_samples_class_mlp (MLPHandle) * 释放训练样本内存
200--- 最大迭代次数1--- 每次迭代的样本数0.01--- 目标误差
2.4 第四步:分类新物体
读取包含未知物体的图像,用相同流程提取特征,然后调用分类器:
halcon
for J := 1 to 4 by 1
read_image (Image, 'rings/mixed_' + J$'02d')
segment (Image, Objects)
classify (Objects, MLPHandle, Classes)
disp_obj_class (Objects, Classes)
endfor
classify 程序:
halcon
procedure classify (Regions, MLPHandle, Classes)
count_obj (Regions, Number)
Classes := []
for J := 1 to Number by 1
select_obj (Regions, Region, J)
get_features (Region, Features)
classify_class_mlp (MLPHandle, Features, 1, Class, Confidence)
Classes := [Classes, Class]
endfor
return ()
结果可视化 --- 不同类别用不同颜色显示:
halcon
procedure disp_obj_class (Regions, Classes)
count_obj (Regions, Number)
Colors := ['yellow', 'magenta', 'green']
for J := 1 to Number by 1
select_obj (Regions, Region, J)
dev_set_color (Colors[Classes[J - 1]])
dev_display (Region)
endfor
return ()
2.5 第五步:释放资源
halcon
clear_class_mlp (MLPHandle)
3. 理论背景
3.1 分类的基本概念
通常,分类是将一个物体分类为几个类别之一。
示例: 你有包含柑橘的灰度图像,已从图像中提取区域,每一个区域表示一种水果。现在想要将桔子从柠檬中分出。
- 特征选择 :面积(桔子通常比柠檬大)以及形状(区域的
circularity,桔子比柠檬更圆) - 特征向量:特征被排列在特征向量的数组中
- 特征空间:特征向量中的特征跨越了一个特征空间,每个特征通过一个轴表示
3.1.1 特征与特征空间
以柑橘分类为例:要区分桔子和柠檬,可以提取每个水果区域的面积 和圆度作为特征。

将每个水果的特征向量绘制在 2D 图中:

- 即使区域的尺寸和圆度有变化,可以看到它们足够相似来创建一个集群
- 分类器的目的就是分开集群并将每一个特征向量分配为其中的一个集群
- 桔子(面积大、更圆)聚集在右上方
- 柠檬(面积小、更长)聚集在左下方
- 分类器的目标就是找到一条分界线将两个集群分开
3.1.2 线性与非线性分类器
- 线性分类器:使用直线(2D)、平面(3D)或超平面(高维)分离集群
- 非线性分类器:使用曲面分离更复杂的集群结构
当特征超过3个时,无法直接可视化,但原理相同------在高维空间中找到分离超平面。
3.2 Euclidean与Hyperbox 分类器
这两种是最简单的分类方法,主要用于图像分割中的像素分类。
3.2.1 Euclidean 分类器(最小距离分类器)
- 在集群中心周围构建圆形(2D)或超球体(高维)
- 特征向量距离哪个集群中心最近,就属于哪个类
- 仅适用于低维特征空间
3.2.2 Hyperbox 分类器
- 使用轴平行的立方体(hyperboxes)划定每个类的范围
- 相当于多维空间中的"阈值法"------每个特征轴上定义一个取值范围
- 对于每个类,特征空间的每个轴确定特定的值范围
- 如果一个特征向量位于特定类的所有范围内,它将被分配到该类
- hyperboxes 可以重叠

局限性:这两种方法只适合低维特征(如颜色分割),不推荐用于一般分类或 OCR。
3.3 多层感知器(MLP)
MLP是一种前馈神经网络,由输入层、一个或多个隐藏层和输出层组成。
核心原理:
- 输入层接收特征向量
- 隐藏层通过非线性激活函数对特征进行变换
- 输出层给出每个类别的概率
关键参数:
| 参数 | 说明 | 调优建议 |
|---|---|---|
| 隐藏层神经元数 | 决定网络容量 | 过多 → 过拟合;过少 → 欠拟合 |
| 激活函数 | 'softmax'(多分类)或 'linear'(回归) |
多分类用 'softmax' |
| 预处理 | 'normalization' / 'principal_components' |
推荐 'normalization' |
优缺点:
- ✅ 分类速度快
- ✅ 支持多分类
- ✅ 可评估每个类别的概率
- ❌ 训练较慢(需要多次迭代)
- ❌ 不支持 novelty detection
- ❌ 训练数据需一次性提供
3.4 支持向量机(SVM)
SVM的核心思想:在特征空间中找到一个最大间隔超平面 来分离不同类别。
SVM可以处理非线性的特征。没有非线性的超平面被获取,而是特征空间被转换到一个高维的空间,使特征变成各自线性的,之后通过线性分类器分类。
3.4.1 从线性到非线性
对于线性不可分的问题,SVM使用核函数将特征映射到更高维空间,使其变得线性可分:

在原始2D空间中无法用直线分开的两类,映射到3D后可以用平面分离。
3.4.2 支持向量与最大间隔
SVM选择的超平面使得两类之间的间隔(margin)最大化。位于间隔边界上的训练样本就是支持向量(Support Vectors) :

只有支持向量决定了分类边界,其他训练样本可以丢弃。
3.4.3 分类公式
给定特征向量 z \mathbf{z} z,SVM 的分类决策函数为:
f ( z ) = sign ( ∑ i = 1 n s v α i y i K ( x i , z ) + b ) f(\mathbf{z}) = \text{sign}\left(\sum_{i=1}^{n_{sv}} \alpha_i y_i \, K(\mathbf{x}_i, \mathbf{z}) + b\right) f(z)=sign(i=1∑nsvαiyiK(xi,z)+b)
其中:
- x i \mathbf{x}_i xi --- 支持向量
- y i ∈ { + 1 , − 1 } y_i \in \{+1, -1\} yi∈{+1,−1} --- 类别标签
- α i \alpha_i αi --- 权重系数
- b b b --- 偏置项
- K ( ⋅ , ⋅ ) K(\cdot, \cdot) K(⋅,⋅) --- 核函数
3.4.4 核函数类型
① 线性核
K ( x , y ) = x ⋅ y K(\mathbf{x}, \mathbf{y}) = \mathbf{x} \cdot \mathbf{y} K(x,y)=x⋅y
仅用于线性或近似线性的分类任务。KernelParam 参数被忽略。
② RBF 核(径向基函数核)--- 推荐
K ( x , y ) = exp ( − γ ∥ x − y ∥ 2 ) K(\mathbf{x}, \mathbf{y}) = \exp\left(-\gamma \|\mathbf{x} - \mathbf{y}\|^2\right) K(x,y)=exp(−γ∥x−y∥2)
KernelParam控制 γ \gamma γ 值- γ \gamma γ 大 → 每个训练向量都成为支持向量 → 过拟合,速度慢
- γ \gamma γ 小 → 支持向量太少 → 欠拟合
- 经验 :从较小的 γ \gamma γ 开始,逐步增大
③ 多项式核
K ( x , y ) = ( x ⋅ y + c ) d K(\mathbf{x}, \mathbf{y}) = (\mathbf{x} \cdot \mathbf{y} + c)^d K(x,y)=(x⋅y+c)d
KernelParam控制度 d d d- d > 10 d > 10 d>10 可能导致数值问题
- 仅在 RBF 效果不佳时尝试
推荐:大多数情况下使用 RBF 核。
3.4.5 Multi-class扩展策略
SVM原生只支持二分类。扩展到多分类有两种策略:
| 策略 | 原理 | 分类器数量 | 适用场景 |
|---|---|---|---|
one-versus-one |
每对类别训练一个二分类器,投票决定 | n ( n − 1 ) / 2 n(n-1)/2 n(n−1)/2 | 类别数较少(≤ 10) |
one-versus-all |
每个类别 vs 其余所有类别 | n n n | 类别数较多 |
novelty-detection |
仅训练一类,其余视为异常 | 1 | 异常检测 |
3.4.6 SVM的核心优势
- ✅ 通过核函数处理非线性问题
- ✅ 训练速度比 MLP 快
- ✅ 支持 novelty detection
- ❌ 分类速度比 MLP 慢
- ❌ 内存占用随训练样本增长
3.5 高斯混合模型(GMM)
GMM假设每个类别的特征服从多个高斯分布的混合:
p ( x ∣ class k ) = ∑ j = 1 M w j ⋅ N ( x ∣ μ j , Σ j ) p(\mathbf{x} | \text{class}k) = \sum{j=1}^{M} w_j \cdot \mathcal{N}(\mathbf{x} | \boldsymbol{\mu}_j, \boldsymbol{\Sigma}_j) p(x∣classk)=j=1∑Mwj⋅N(x∣μj,Σj)
核心原理:
- 用多个高斯分布的加权和来拟合每个类别的特征分布
- 分类时计算特征向量属于各类别的概率,取最大者
优缺点:
- ✅ 训练和分类都很快
- ✅ 适合缺陷检测
- ✅ 可评估概率
- ❌ 不适合高维特征空间
- ❌ 对数据分布假设敏感
3.6 K近邻分类器(k-NN)
k-NN是最简单的分类器之一:找到特征空间中距离最近的 k k k 个训练样本,通过投票决定类别。
核心原理:
- 无需显式训练------训练样本本身就是模型
- 分类时计算待分类样本与所有训练样本的距离
- 取最近的 k k k 个样本中出现最多的类别
优缺点:
- ✅ 训练极快(无需训练)
- ✅ 无特征空间维度限制
- ✅ 可随时添加新训练样本
- ❌ 分类速度慢(需遍历所有训练样本)
- ❌ 内存占用大(需存储全部训练数据)
- ❌ 不支持预处理降维
3.7 卷积神经网络(CNN)
CNN是深度学习的代表模型,特别适合图像分类任务。
核心原理:
- 卷积层:通过卷积核提取局部特征(边缘、纹理等)
- 池化层:降低特征维度,增强平移不变性
- 全连接层:将提取的特征映射到类别空间
在 HALCON 中的应用:
- HALCON 提供预训练的CNN模型用于OCR
- 预训练字体Universal覆盖大量常见字体
- 也可通过迁移学习微调自定义模型
优缺点:
- ✅ 自动学习特征,无需手动设计
- ✅ 分类精度高
- ❌ 训练极慢,需要大量数据
- ❌ 模型体积大
4. 如何选择:关键决策指南
4.1 选择分类方法

建议:
- MLP --- 需要快速分类但允许更慢的离线训练时间的应用。完整训练数据应该从一开始就可用。
- SVM --- 获取比其他分类器质量轻微高的应用。分类速度较低,内存需求较大。
- GMM --- 训练和分类都比较快,尤其类别数量少的情况。适合缺陷检测。
- k-NN --- 适合测试特征和训练数据的不同配置。训练非常快,无特征空间维度限制。
- Hyperbox/Euclidean --- 适合低维特征向量,如颜色分类用于图像分割。
OCR 建议: 推荐先尝试预训练字体 Universal(基于CNN),再尝试其他 OCR 分类方法。
快速决策树:
bash
需要分类吗?
├── 是 OCR 任务?
│ └── 先试预训练字体 Universal(CNN)
├── 是图像分割?
│ ├── 通道数 ≤ 3 → 考虑LUT加速
│ └── 低维特征 → Euclidean / Hyperbox
└── 一般分类?
├── 需要 novelty detection? → SVM
├── 需要快速分类? → MLP
├── 类别很少且需快速迭代? → GMM
└── 需要灵活扩展? → k-NN
详细对比:
| 需求 | 推荐 | 理由 |
|---|---|---|
| 分类速度快 | MLP | 在线阶段高效 |
| 训练速度快 | k-NN / GMM | 无需复杂优化 |
| 高精度 | SVM | 最大间隔原则 |
| 内存有限 | GMM | 模型紧凑 |
| 数据持续更新 | k-NN | 可增量添加 |
| 异常检测 | SVM (novelty-detection) | 专为此设计 |
| 图像分割(≤3通道) | LUT 加速的 MLP/SVM/GMM/k-NN | 显著加速 |
重要提示 :如果分类效果不好,问题通常不在分类器本身,而在于特征选择 或训练样本的质量和数量。
4.2 选择合适的特征
特征选择没有固定规则,取决于具体应用。
| 分类任务 | 特征来源 | 说明 |
|---|---|---|
| 一般分类 | 区域特征 + 颜色/纹理 | 手动选择合适的特征算子 |
| 图像分割 | 多通道像素值 | 由分割算子自动提取 |
| OCR | 受限的区域特征集 | 由 OCR 算子内部计算 |
纹理特征:
texture_laws--- 创建纹理滤波图像cooc_feature_image--- 计算灰度共生矩阵特征(energy, correlation, homogeneity, contrast)
HALCON 自动特征选择:
halcon
select_feature_set_mlp (ClassTrainDataHandle, ...)
select_feature_set_svm (ClassTrainDataHandle, ...)
select_feature_set_gmm (ClassTrainDataHandle, ...)
select_feature_set_knn (ClassTrainDataHandle, ...)
这些算子自动评估特征组合,选择最优子集。
4.3 选择训练样本
训练样本必须能代表待分类物体的所有变化。
关键原则:
- 样本要覆盖允许的偏差范围(噪声、尺寸变化、旋转等)
- 每个类别需要足够数量的样本
- 样本不足 → 分类器泛化能力差
样本不足时的技巧:
1. 数据增强 --- 复制现有样本并轻微变换:
- 添加噪声
- 膨胀/腐蚀改变尺寸
- 小角度旋转
2. 类别不均衡时的两阶段分类:
- 第一阶段:好物体 vs 所有缺陷(二分类,样本充足)
- 第二阶段:在缺陷类中细分具体类型
5. 实战:一般分类工作流
5.1 一般方法
MLP、SVM、GMM、k-NN 的工作流程一致:

1. 创建分类器 --- 定义特征维度、类别数等参数
2. 添加训练样本 --- 提取特征,添加到分类器
3. 训练 --- 让分类器学习分类规则
4. 分类 --- 对新物体提取相同特征并分类
5. 释放资源
5.1.1 卤素灯质量检测示例(分类为好/坏/无):
halcon
ClassNames := ['good','bad','none']
5.1.2 创建SVM分类器:
halcon
Nu := 0.05
KernelParam := 0.02
create_class_svm (7, 'rbf', KernelParam, Nu, |ClassNames|, \
'one-versus-one', 'principal_components', 5, SVMHandle)
5.1.3 添加训练样本:
halcon
procedure add_samples_to_svm (ClassNames, SVMHandle, WindowHandle, ReadPath)
for ClassNumber := 0 to |ClassNames| - 1 by 1
list_files (ReadPath + ClassNames[ClassNumber], 'files', Files)
Selection := regexp_select(Files,'.*[.]png')
for Index := 0 to |Selection| - 1 by 1
read_image (Image, Selection[Index])
threshold (Image, Region, 0, 40)
calculate_features (Region, Features)
add_sample_class_svm (SVMHandle, Features, ClassNumber)
endfor
endfor
return ()
5.1.4 特征计算:
halcon
procedure calculate_features (Region, Features)
area_center (Region, Area, Row, Column)
compactness (Region, Compactness)
moments_region_central_invar (Region, PSI1, PSI2, PSI3, PSI4)
convexity (Region, Convexity)
Features := real([Area, Compactness, PSI1, PSI2, PSI3, PSI4, Convexity])
return ()
特征包括:
- 区域的
area - 区域的
compactness - 4 个几何矩 (
PSI1,PSI2,PSI3,PSI4),对平移和一般线性变换不变 - 区域的
convexity
5.1.5 训练:
halcon
train_class_svm (SVMHandle, 0.001, 'default')
5.1.6 分类新物体:
halcon
procedure classify_regions_with_svm (SVMHandle, Colors, ClassNames, ReadPath)
list_files (ReadPath, ['files','recursive'], Files)
Selection := regexp_select(Files,'.*[.]png')
for Index := 0 to |Selection| - 1 by 1
read_image (Image, Selection[Index])
threshold (Image, Region, 0, 40)
calculate_features (Region, Features)
classify_class_svm (SVMHandle, Features, 1, Class)
endfor
return ()
5.1.7 释放内存:
halcon
clear_class_svm (SVMHandle)
5.1.8 离线/在线分离:
- 使用
write_class_svm保存训练的分类器 - 使用
read_class_svm在线读取并分类 - 使用
write_samples_class_svm/read_samples_class_svm保存/读取训练样本
5.2 算子概览
5.2.1基本步骤
| 步骤 | MLP | SVM | GMM | k-NN |
|---|---|---|---|---|
| 创建 | create_class_mlp |
create_class_svm |
create_class_gmm |
create_class_knn |
| 添加样本 | add_sample_class_mlp |
add_sample_class_svm |
add_sample_class_gmm |
add_sample_class_knn |
| 训练 | train_class_mlp |
train_class_svm |
train_class_gmm |
train_class_knn |
| 保存样本 | write_samples_class_mlp |
write_samples_class_svm |
write_samples_class_gmm |
--- (内置) |
| 读取样本 | read_samples_class_mlp |
read_samples_class_svm |
read_samples_class_gmm |
--- |
| 保存模型 | write_class_mlp (.gmc) |
write_class_svm (.gsc) |
write_class_gmm (.ggc) |
write_class_knn (.gnc) |
| 读取模型 | read_class_mlp |
read_class_svm |
read_class_gmm |
read_class_knn |
| 分类 | classify_class_mlp |
classify_class_svm |
classify_class_gmm |
classify_class_knn |
| 释放 | clear_class_mlp |
clear_class_svm |
clear_class_gmm |
clear_class_knn |
5.2.2 高级操作
| 操作 | MLP | SVM | GMM | k-NN |
|---|---|---|---|---|
| 概率评估 | evaluate_class_mlp |
--- | evaluate_class_gmm |
--- |
| 减少支持向量 | --- | reduce_class_svm |
--- | --- |
| 获取支持向量 | --- | get_support_vector_num_class_svm |
--- | --- |
| 预处理信息 | get_prep_info_class_mlp |
get_prep_info_class_svm |
get_prep_info_class_gmm |
--- |
| 参数查询 | get_params_class_mlp |
get_params_class_svm |
get_params_class_gmm |
get_params_class_knn |
| 样本查询 | get_sample_class_mlp |
get_sample_class_svm |
get_sample_class_gmm |
get_sample_class_knn |
获取训练样本信息:
get_sample_class_mlp/get_sample_class_svm/get_sample_class_gmm/get_sample_class_knnget_sample_num_class_mlp/get_sample_num_class_svm/get_sample_num_class_gmm/get_sample_num_class_knn
获取预处理信息:
get_prep_info_class_mlp/get_prep_info_class_svm/get_prep_info_class_gmm- k-NN 不支持此功能
获取参数:
get_params_class_mlp/get_params_class_svm/get_params_class_gmm/get_params_class_knn
特定分类器高级操作:
- MLP/GMM :
evaluate_class_mlp/evaluate_class_gmm--- 评估特征向量属于特定类的概率 - SVM :
reduce_class_svm--- 减少支持向量数量以加速在线分类 - SVM :
get_support_vector_num_class/get_support_vector_class--- 获取支持向量数量/索引 - k-NN :
set_params_class_knn--- 设置 k 值、结果类型等参数
5.3 SVM参数调优详解
SVM的效果主要取决于两个核心参数:
5.3.1 核心参数
① Nu(正则化常数)
- 控制训练误差的上界和支持向量数量的下界
- 取值范围: ( 0 , 1 ) (0, 1) (0,1)
- 经验值:设为预期误差率(如
0.05表示最大 5% 训练误差) - 过大 → 数据集膨胀,速度下降,可能报错
- 过小 → 数值不稳定,分类错误多
② KernelParam(核参数 γ \gamma γ)
- 仅RBF核和多项式核需要设置
- RBF 核中控制支持向量的"影响范围"
- 过大 → 过拟合(每个样本都成为支持向量)
- 过小 → 欠拟合(支持向量不足以描述边界)
调优策略 :从较小的 Nu 和 γ \gamma γ 开始,逐步增大。建议通过交叉验证 搜索最优的 Nu- γ \gamma γ 组合。
5.3.2 速度优化参数
③ Preprocessing
'normalization'--- 通常就足够,提高数值稳定性'principal_components'--- 配合 RBF 核可显著加速(甚至比 MLP 更快)
④ reduce_class_svm
- 减少支持向量数量以加速在线分类
- 从
MaxError = 0.0001开始,逐步增大
5.3.3 其他参数
| 参数 | 说明 | 建议 |
|---|---|---|
NumFeatures |
特征维度 | 可达 500 |
NumClasses |
类别数 | --- |
Mode |
多分类策略 | ≤10 类用 'one-versus-one',否则用 'one-versus-all' |
NumComponents |
PCA 降维后的维度 | 用 get_prep_info_class_svm 确定最优值 |
Epsilon |
训练停止阈值 | 通常用默认值 0.001 |
5.4 Parameter Setting for SVM
SVM分类中需要调整的重要参数:
核心参数(影响分类质量):
Nu(create_class_svm)KernelParam(create_class_svm)
速度优化参数:
Preprocessing(create_class_svm):'rbf'+'principal_components'组合可显著加速 SVMMaxError(reduce_class_svm)
5.4.1 调整 create_class_svm
参数 NumFeatures:
指定用于分类以及训练的特征向量的维度。相比 GMM 分类器,500 个特征仍然是可用的。
参数 KernelType / KernelParam:
建议大多数情况下使用 RBF 核 ('rbf')。
如果 KernelType = 'rbf',KernelParam 用来调整误差曲线的 γ \gamma γ,需要仔细调整:
- γ \gamma γ 值过高 → 支持向量数量增加 → 过度拟合,速度减小
- γ \gamma γ 值过低 → 支持向量不足 → 欠拟合
建议: 从较小的 γ \gamma γ 值开始,逐渐增加。同时搜索合适的 Nu- γ \gamma γ 对,通过交叉验证实现。
其他核选择:
- 线性核 (
'linear'):用于类别各自线性的情况,KernelParam无意义 - 多项式核 (
'polynomial_homogeneous'/'polynomial_inhomogeneous'):很少使用,只在 RBF 不成功时尝试
参数 Nu:
- 规范类别的区分,调整训练误差的上界和支持向量数量的下界
- 值必须在 0 和 1 之间
- 一般设定为指定数据集的期望误差率(如
0.05对应最大 5% 训练误差) - 非常大的 Nu → 大的数据集,速度显著减小,可能导致错误信息
- 非常小的 Nu → 不稳定的数字,许多特征向量被错误分类
建议: 从一个小的值开始,逐渐增加。同时搜索合适的 Nu- γ \gamma γ 对。
参数 NumClasses:
指定类别的数量。
参数 Mode:
| Mode | 说明 | 适用场景 |
|---|---|---|
'novelty-detection' |
超平面位于训练数据周围,隐式从拒绝域分离 | 仅 'rbf' 核 |
'one-versus-one' |
每个类别对创建二值分类器, n ( n − 1 ) / 2 n(n-1)/2 n(n−1)/2 个分类器 | 少量类别,快速 |
'one-versus-all' |
每个类别与剩余数据对比, n n n 个分类器 | 大量类别 |
参数 Preprocessing / NumComponents:
| Preprocessing | 说明 |
|---|---|
'none' |
无预处理 |
'normalization' |
规范化(推荐大多数情况) |
'principal_components' |
PCA 降维 |
'canonical_variates' |
线性判别式分析 |
如果使用
'principal_components'或'canonical_variates',可用get_prep_info_class_svm确定最优组件数量。
5.4.2 调整 add_sample_class_svm
参数 Features:
- 包含样本的特征向量(值的元组)
- 每个值描述一个特定的数值特征
- 特征向量必须由实数组成(整数需转换为实数,否则报错)
参数 Class:
- 包含特征向量所属类的 ID
- ID 是
0到Number of Classes - 1之间的整数
5.4.3 调整 train_class_svm
参数 Epsilon:
- 训练 SVM 是逐渐优化确定类别边界的函数
- 优化在函数的梯度低于阈值后停止,阈值通过
Epsilon设定 - 大多数情况下应设置为默认值
0.001 - 太小的阈值 → 优化变慢,不改善识别率
- 太大的阈值 → 优化在最佳点前暂停,识别率不满意
何时调整:
- 非常小的
Nu值以及非常小或不平衡的训练数据 → 设置比默认值小 - 交叉验证搜索 Nu- γ \gamma γ 对期间 → 选择一个大的值加速
参数 TrainMode:
- 默认:所有样本在一步中训练
'add_sv_to_train_set':附加新的样本集到之前的训练中(注意:只使用之前训练的支持向量)
5.4.4 Adjusting reduce_class_svm
减少训练返回的支持向量数量,加速在线分类。
参数 Method / MinRemainingSV / MaxError:
Method = 'bottom_up':通过迭代合并支持向量减少数量- 直到达到
MinRemainingSV设置的最小数量,或累积最大误差超过MaxError阈值
建议: 从
MaxError的小值开始(如0.0001),逐步增加。通过get_support_vector_num_class检查剩余支持向量数量,通过classify_class_svm分类测试数据检查分类率。
5.4.5 Adjusting classify_class_svm
参数 Num:
Num = 1:只搜索最可能的类Num = 2:也搜索第二可能的类(例如类别重叠时)- 如果
Mode = 'novelty-detection',Num必须设置为1
参数 Class(输出):
| Mode | 返回内容 |
|---|---|
'one-versus-one' |
按 sub-classifiers 的 vote 数排序的类别 |
'one-versus-all' |
按每个 sub-classifier 的值排序的类别 |
'novelty-detection' |
1 = 属于训练类,0 = 属于拒绝类 |
5.4.6 Adjusting clear_class_svm
halcon
clear_class_svm (SVMHandle)
销毁分类器,释放内存。
6.SVM算子API参考
add_class_train_data_svm
bash
add_class_train_data_svm( : : SVMHandle, ClassTrainDataHandle : )
添加训练数据到 SVM。
算子 add_class_train_data_svm 添加 ClassTrainDataHandle 中指定的训练数据到 SVMHandle 指定的SVM中。
| 参数 | 方向 | 类型 | 说明 |
|---|---|---|---|
SVMHandle |
input | class_svm |
SVM 句柄 |
ClassTrainDataHandle |
input | class_train_data |
训练数据句柄 |
add_sample_class_svm
bash
add_sample_class_svm( : : SVMHandle, Features, Class : )
添加单个训练样本。Features 长度须等于 NumFeatures;Class 范围为 0 ~ NumClasses-1。
add_sample_class_svm 添加一个训练样本到 SVMHandle 指定的 SVM 中。训练样本通过 Features 和 Class 给出。
Features 是样本的特征向量,其长度为 create_class_svm 中指定的 NumFeatures。
Class 是样本的目标,其必须在 0 到 NumClasses-1 范围内。
在有无检测的特定情况下,class 需被设置为 0,因为只设定有一个类。在 SVM 通过 train_class_svm 训练之前,训练样本需要使用算子 add_sample_class_svm 添加到 SVM 中。
当前存储的训练样本可以通过 get_sample_num_class_svm 查询,通过 get_sample_class_svm 读取。
通常,通过算子 write_samples_class_svm 将训练样本保存到文件以方便重读使用。
| 参数 | 方向 | 类型 | 说明 |
|---|---|---|---|
SVMHandle |
input | class_svm |
SVM 句柄 |
Features |
input | real-array |
特征向量(必须为实数) |
Class |
input | number |
类别 ID |
classify_class_svm
bash
classify_class_svm( : : SVMHandle, Features, Num : Class )
对特征向量进行分类。
classify_class_svm 通过 SVMHandle 表示的 SVM 计算特征向量 Features 中最好的 Num 个类,并返回他们在 Class 中。
- 如果分类器以
Mode = 'one-versus-one'创建,类别通过 sub-classifiers 中选择的分类的数量排序。 - 如果使用
Mode = 'one-versus-all',类别通过每一个 sub-classifier 的值排序。 - 如果分类器通过
Mode = 'novelty-detection'创建,其确定特征向量和训练数据属于同一个类(Class = 1)还是被认为是不同类(Class = 0)。这种情况下Num需被设置为1。
| 参数 | 方向 | 类型 | 说明 |
|---|---|---|---|
SVMHandle |
input | class_svm |
SVM 句柄 |
Features |
input | real-array |
特征向量 |
Num |
input | integer |
返回的最佳类别数(默认 1) |
Class |
output | integer-array |
分类结果 |
返回值含义取决于 Mode:
'one-versus-one':按投票数排序'one-versus-all':按子分类器值排序'novelty-detection':1= 属于训练类,0= 异常
clear_class_svm
bash
clear_class_svm( : : SVMHandle : )
销毁SVM,释放内存。
clear_samples_class_svm
bash
clear_samples_class_svm( : : SVMHandle : )
清空训练样本。仅在训练和分类在同一进程时使用,可释放样本内存。
create_class_svm
bash
create_class_svm( : : NumFeatures, KernelType, KernelParam, Nu, NumClasses, Mode,
Preprocessing, NumComponents : SVMHandle )
创建SVM分类器。详细参数见5.3 节
create_class_svm 创建一个可用于模式分类识别的支持向量机。要被分类的模式的维数在 NumFeatures 中指定,不同类别的数量通过 NumClasses 指定。
对于一个类别是线性可分的二元分类问题,SVM算法利用训练数据集中的数据向量来在不同的类别间创建各自最佳的超平面。就不同类的convex hulls 间的 margin最大来说,该超平面是最佳的。位于 margin 的训练模式定义了超平面并被称作 support vectors (SV)。
分类公式:
f ( z ) = sign ( ∑ i = 1 n s v α i y i ( x i ⋅ z ) + b ) f(\mathbf{z}) = \text{sign}\left(\sum_{i=1}^{n_{sv}} \alpha_i y_i (\mathbf{x}_i \cdot \mathbf{z}) + b\right) f(z)=sign(i=1∑nsvαiyi(xi⋅z)+b)
其中:
- x i \mathbf{x}_i xi 是支持向量
- y i y_i yi 编码它们的类别成员 ( ± 1 \pm 1 ±1)
- α i \alpha_i αi 是权重系数
- b b b 是超平面到原点的距离
- n s v n_{sv} nsv 是支持向量的数量
注意: 只有原始训练数据的一个子集对于判定边界的定义是必须的,非支持向量的数据向量被丢弃。分类速度依赖于支持向量和要分类的特征向量间点积的计算。
非线性扩展:
对于各类别间不是线性的分类问题,算法以两种方式延伸:
-
差额变量 :一定数量的误差通过使用差额变量被补偿。正则化参数
Nu是一个训练错误数量的渐进上界以及关于支持向量数量的渐进下界。作为经验法则,参数Nu应该被设置为应用指定误差率的一个先前预期(例如0.01对应最大 1% 训练误差)。 -
核函数:SVM 唯一计算特征向量间的点积,可以包含一个核函数到训练以及测试算法中。这表示点积被核函数代替,隐式的在更高维度特征空间中执行了点积。
核函数类型:
-
线性核 (
KernelType = 'linear'):计算原始点积,仅用于线性或近似线性的分类任务。KernelParam被忽略。 -
RBF 核 (
KernelType = 'rbf'):定义为:
K ( x , y ) = exp ( − γ ∥ x − y ∥ 2 ) K(\mathbf{x}, \mathbf{y}) = \exp\left(-\gamma \|\mathbf{x} - \mathbf{y}\|^2\right) K(x,y)=exp(−γ∥x−y∥2)
参数 KernelParam 用来选择 γ \gamma γ。大的 γ \gamma γ 值(小的周围影响)意味着每一个训练向量变成一个支持向量,导致过拟合。太小的 γ \gamma γ 值(大的周围影响)导致太少的支持向量,导致欠拟合。
- 多项式核 (
KernelType = 'polynomial_homogeneous'或'polynomial_inhomogeneous'):
K ( x , y ) = ( x ⋅ y + c ) d K(\mathbf{x}, \mathbf{y}) = (\mathbf{x} \cdot \mathbf{y} + c)^d K(x,y)=(x⋅y+c)d
多项式核的度通过 KernelParam 设置,太高的度 ( d > 10 d > 10 d>10) 可能会导致大量问题。
经验建议: RBF 核对于大部分分类问题提供了好的选择,应该被用在大部分情况下。
Mode 参数:
Mode = 'one-versus-all':每一个类别都和剩余训练数据相比较。测试期间,最大输出的类被选择。Mode = 'one-versus-one':在每一个单独类别之间创建了一个二元的分类器。测试期间,赢得大部分 votes 的类别被选择。Mode = 'novelty-detection':测试数据仅通过训练数据的成员分类,NumClasses必须被设置为1。
预处理参数:
Preprocessing = 'none':特征向量不变的被传递到 SVM 中。Preprocessing = 'normalization':特征向量被规范化。对于多项式核,训练数据的最小以及最大值被转换到 -1 和 +1 之间。对于 RBF 核,数据通过减去均值并除以标准差被规范化。Preprocessing = 'principal_components':主成份分析(PCA)。首先规范化,之后计算正交变换。NumComponents确定使用多少转换的组成部分。Preprocessing = 'canonical_variates':规范化训练向量,之后 decorrelates the training vectors on average over all classes,同时最大分离单独种类的平均值。也被称作线性判别式分析。
| 参数 | 方向 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
NumFeatures |
input | integer |
10 | 输入变量(特征)数量,Restriction: >= 1 |
KernelType |
input | string |
'rbf' |
核类型:'linear', 'rbf', 'polynomial_inhomogeneous', 'polynomial_homogeneous' |
KernelParam |
input | real |
0.02 | 核函数附加参数(RBF: γ \gamma γ,多项式: 度) |
Nu |
input | real |
0.05 | 正则化常数,Restriction: 0.0 < Nu < 1.0 |
NumClasses |
input | integer |
5 | 类别数量,Restriction: >= 1 |
Mode |
input | string |
'one-versus-one' |
'novelty-detection', 'one-versus-all', 'one-versus-one' |
Preprocessing |
input | string |
'normalization' |
'none', 'normalization', 'principal_components', 'canonical_variates' |
NumComponents |
input | integer |
10 | 预处理参数:转换特征数量 |
SVMHandle |
output | class_svm ; integer |
--- | SVM handle |
evaluate_class_svm
bash
evaluate_class_svm( : : SVMHandle, Features : Result )
仅用于 novelty-detection 模式。返回值 > 1.0 表示属于训练类,< 1.0 表示异常。
- 如果特征向量位于类别内,返回值大于
1.0 - 如果特征向量位于类别边界外(即异常点),返回值小于
1.0
get_class_train_data_svm
bash
get_class_train_data_svm( : : SVMHandle : ClassTrainDataHandle )
获取 SVM 的训练数据句柄。
get_params_class_svm
bash
get_params_class_svm( : : SVMHandle : NumFeatures, KernelType, KernelParam, Nu,
NumClasses, Mode, Preprocessing, NumComponents )
返回创建SVM时的参数。
返回 create_class_svm 创建 SVM 时的参数。在 SVM 从文件中读取出的情况下尤其有用。
get_prep_info_class_svm
bash
get_prep_info_class_svm( : : SVMHandle, Preprocessing : InformationCont, CumInformationCont )
计算预处理后各成分的信息含量,用于确定最优 NumComponents。
get_sample_class_svm
bash
get_sample_class_svm( : : SVMHandle, IndexSample : Features, Target )
返回指定索引的训练样本。
get_sample_num_class_svm
bash
get_sample_num_class_svm( : : SVMHandle : NumSamples )
返回 SVM 方法中存储在训练数据中样本的数量。
get_support_vector_class_svm
bash
get_support_vector_class_svm( : : SVMHandle, IndexSupportVector : Index )
返回指定索引的支持向量。
get_support_vector_num_class_svm
bash
get_support_vector_num_class_svm( : : SVMHandle : NumSupportVectors, NumSVPerSVM )
返回一个 SVM 中支持向量的数量。
read_class_svm
bash
read_class_svm( : : FileName : SVMHandle )
read_class_svm 读取一个已经通过 write_class_svm 存储的 SVM。由于 SVM 的训练可以使用相对长的时间,SVM 通常是离线训练并通过 write_class_svm 保存到文件。在线过程,SVM 通过 read_class_svm 读取并用于 classify_class_svm 的分类。
HALCON 中 SVM 的默认文件扩展名是 .gsc。
参数:
| 参数 | 方向 | 类型 | 说明 |
|---|---|---|---|
FileName |
input | filename.read ; string |
文件名,扩展名: .gsc |
SVMHandle |
output | class_svm ; integer |
SVM handle. |
read_samples_class_svm
bash
read_samples_class_svm( : : SVMHandle, FileName : )
从文件读取训练样本并添加到 SVM。特征维度须与 create_class_svm 一致。
read_samples_class_svm 从 FileName 中读取训练样本并添加到 SVMHandle 给出的 SVM 中。调用前 SVM 必须已通过 create_class_svm 创建。
注意: 训练样本应该有正确的维度。存储在
FileName中的特征向量以及目标应该有create_class_svm中指定的长度NumFeatures和NumClasses。
reduce_class_svm
bash
reduce_class_svm( : : SVMHandle, Method, MinRemainingSV, MaxError : SVMHandleReduced )
减少支持向量数量以加速分类。Method 目前仅支持 'bottom_up'。
select_feature_set_svm
bash
select_feature_set_svm( : : ClassTrainDataHandle, SelectionMethod, GenParamName,
GenParamValue : SVMHandle, SelectedFeatureIndices, Score )
自动选择最优特征组合。
train_class_svm
bash
train_class_svm( : : SVMHandle, Epsilon, TrainMode : )
训练SVM。Epsilon 控制优化停止阈值(默认 0.001)。TrainMode 默认 'default'。
write_class_svm
bash
write_class_svm( : : SVMHandle, FileName : )
保存SVM到文件(扩展名 .gsc)。不包含训练样本。
write_samples_class_svm
bash
write_samples_class_svm( : : SVMHandle, FileName : )
保存训练样本到文件。
write_class_svm 将 SVMHandle 保存到文件 FileName 中。默认 SVM 的 HALCON 文件扩展名是 .gsc。write_class_svm 通常在 train_class_svm 训练之后调用。
注意:
write_class_svm不保存训练样本。对于该目的,应该使用write_samples_class_svm。