1 前言
基于支持向量机(SVM)和梯度方向直方图(HOG)的目标检测技术,是手工特征目标检测的巅峰之作。在深度学习出现之前,SVM作为机器学习中表现最好的算法之一,与HOG特征相结合,在行人检测等领域得到了广泛应用。本文将尝试使用SVM+HOG的方案进行车牌识别的第一个步骤:车牌检测。相关数据与代码下载地址:下载地址
2 支持向量机
SVM最早由Vladimir N. Vapnik和Alexey Ya. Chervonenkis在1963年提出,用于解决分类问题。随后的几十年里,SVM经历了不断的发展和完善。其中,Corinna Cortes和Vapnik在1993年提出了SVM的soft margin版本,并在1995年发表,这一版本在后续的研究和应用中得到了广泛使用。
2.1 支持向量机的基本原理
**最优分类超平面 **
- 支持向量机的核心思想是通过在特征空间中找到一个最优的超平面,将不同类别的样本点尽可能地分开。这个超平面被称为决策边界,它能够最大化不同类别之间的间隔,从而提高分类的准确性和泛化能力。
- 最优分类超平面方程为:w·x+b=0,其中w是权重向量,“·”是向量点积,x是输入向量,b是一个阈值。
- 支持向量
在支持向量机中,选择的决策边界是依赖于支持向量的样本点的。这些支持向量是距离决策边界最近的样本点,对于决策边界的确定起到了关键作用,因为它们决定了分类器的边界位置和形状。
2.2 支持向量机的变体
支持向量机算法有几种变体,其中最常见的是线性支持向量机和非线性支持向量机。
-
线性支持向量机
- 通过一个线性超平面来划分数据,并且在处理高维数据时表现出色。
- 能满足与两个类边界分割平面等距,且使得两个类边界分割平面之间的间隔(margin)最大的分类超平面为最优分类超平面。每个类边界分割平面到超平面的距离均为1/‖w‖,其中‖w‖是欧式模函数。
- 在线性支持向量机中允许一定数量的样本点位于超平面的错误一侧,这样可以处理一些数据不是完全线性可分的情况。这种允许少量样本点违反约束的情况通过引入软间隔(soft margin)和惩罚函数C来实现。软间隔允许在最大化间隔的同时,对一些误分类的样本进行一定程度的容忍,以提高模型的鲁棒性和泛化能力。
-
非线性支持向量机
- 当数据集不是线性可分时,需要使用非线性支持向量机来建模更复杂的决策边界。
- 基本思路是引入核函数将数据从原始空间映射到一个高维特征空间,使得在高维空间中的数据变得线性可分。然后,在高维空间中寻找最优的超平面,即最大间隔超平面,来进行分类。
- 常用的核函数主要有多项式核函数、径向基核函数(定义一个球形核,中心为x,函数中分母部分为半径的平方,支持向量机是一种径向基分类器)、S型核函数(采用S函数为点积,实际是定义了一种包含隐藏层的多层感知机,其隐含节点的数目由算法自动确定)等。
3 梯度方向直方图
3.1 定义
梯度方向直方图是一种通过计算图像局部区域的梯度方向直方图来构成特征的方法。该方法能够很好地描述图像的局部梯度方向和梯度强度分布特性,从而有效地用于目标检测。
3.2 计算方法
-
图像预处理
- 将图像灰度化,以简化后续的计算过程。
- 进行Gamma校正,以减少光度对实验的影响,使图像更加均衡。但这一步骤是可选的,因为实验证明其对最终结果的影响不大。
-
计算梯度值
- 对于图像中的每个像素点,计算其水平梯度和竖直梯度。这通常通过使用Sobel算子等梯度计算方法来实现。
- 根据梯度的大小和方向,为每个像素点分配一个梯度强度和梯度方向值。
-
构建细胞单元(Cell)
- 将图像分割成小的连通区域,这些区域被称为细胞单元。细胞单元是HOG特征描述的基本单位。
- 在每个细胞单元内,统计梯度方向的直方图。这通常是将梯度方向划分为若干个区间(bins),并统计每个区间内的梯度强度累加值。
-
构建块(Block)并进行归一化
- 将多个细胞单元组合成一个更大的区域,这个区域被称为块。块用于对细胞单元的梯度直方图进行归一化处理,以减少光照和对比度的变化对特征的影响。
- 归一化方法通常是将块内所有细胞单元的梯度直方图向量进行归一化,得到归一化后的特征向量。
-
组合特征向量
- 将图像中所有块的归一化特征向量组合起来,形成一个大的特征向量。这个特征向量就是图像的HOG特征描述子。
- 将图像中所有块的归一化特征向量组合起来,形成一个大的特征向量。这个特征向量就是图像的HOG特征描述子。
4 基于SVM和HOG的车牌检测
4.1 车牌预备知识
我们国家的车牌的有着严格的尺寸规定,长度440mm,高度140mm,比例大致为1:3。我们可以利用这个先验知识,设计出车牌检测的滑动窗口比例,提高检测概率。
4.2 收集训练数据集
从CCPD2019数据集的base目录中,随机抽取500张样本,裁剪车牌区域作为正样本,抹黑车牌区域后的图像作为负样本。
正样本截图如下:
负样本截图如下:
4.3 opencv训练脚本
- 创建SVM分类器。
//创建一个SVM分类器
cv::Ptr< cv::ml::SVM > svm = cv::ml::SVM::create();
svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 1000, 1e-3));
//使用线性SVM
svm->setKernel(cv::ml::SVM::LINEAR);
svm->setType(cv::ml::SVM::C_SVC);
- 创建HOG特征提取器。
//定义检测器的宽度和高度,必须是8的倍数,宽度和高度的比例大致为3:1
const int detector_width = 192;
const int detector_heigt = 64;
cv::Size detector_size(detector_width, detector_heigt);
//定义HOG特征提取器
cv::HOGDescriptor hog_descriptor;
//设置HOG特征提取器的尺寸
hog_descriptor.winSize = detector_size;
- 导入样本,并提取HOG特征。
//定义标签数组
std::vector< int > labels;
//导入正样本,并进行特征提取
std::cout << "--->载入正样本..." << std::endl;
std::vector<cv::Mat> feature_set = collectFeatureSet(posi_dir, hog_descriptor, true);
labels.assign(feature_set.size(), +1);
std::cout << "正样本数量:" << feature_set.size() << std::endl;
//导入负样本,并进行特征提取
std::cout << "--->载入负样本..." << std::endl;
std::vector<cv::Mat> nega_feature_buffer = collectFeatureSet(nega_dir, hog_descriptor, false);
labels.insert(labels.end(), nega_feature_buffer.size(), -1);
feature_set.insert(feature_set.end(), nega_feature_buffer.begin(), nega_feature_buffer.end());
std::cout << "负样本数量:" << nega_feature_buffer.size() << std::endl;
- 创建训练数据矩阵,并进行训练。
cv::Mat train_data;
convertToML(feature_set, train_data);
cv::Ptr<cv::ml::TrainData> svm_train_auto_data = cv::ml::TrainData::create(train_data, cv::ml::SampleTypes::ROW_SAMPLE, labels);
std::cout << "--->开启训练SVM..." << std::endl;
svm->trainAuto(svm_train_auto_data);
4.4 模型测试
- 导入训练好的SVM模型。
//目标检测模型保存路径和名称
const std::string save_pathname("./car_plane_detector.yaml");
//测试图像路径
const std::string test_dir("./test");
//导入目标检测模型
cv::HOGDescriptor hog_descriptor;
hog_descriptor.load(save_pathname);
- 使用利用的detectMultiScale函数进行多尺度车牌检测。
//检测结果Box
std::vector< cv::Rect > detections;
hog_descriptor.detectMultiScale(image, detections);
for (size_t j = 0; j < detections.size(); j++)
{
rectangle(image, detections[j], cv::Scalar(0, 255, 0), 2);
printf("%d %d\n", detections[j].width, detections[j].height);
}
cv::imshow("检测结果", image);
小结论
- 在深度学习时期之前,SVM结合HOG特征的目标检测方案是比较流行的方案,主要体现在行人检测领域。
- 手工特征的目标检测的调试难度较大,需要对SVM的训练参数进行精选调整。