EasyPR源码剖析(7):车牌判断之SVM
前面的文章中我们主要介绍了车牌定位的相关技术,但是定位出来的相关区域可能并非是真实的车牌区域,EasyPR通过SVM支持向量机,一种机器学习算法来判定截取的图块是否是真的“车牌”,本节主要对相关的技术做详细的介绍。
注:SVM相关内容可以详细参考周志华老师的《机器学习》和一篇名为《支持向量机通俗导论(理解SVM的三层境界)》的文章。
一、SVM简介
支持向量机,其英文名为 support vector machine,故一般简称SVM,通俗来讲,它是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的线性分类器,其学习策略便是间隔最大化,最终可转化为一个凸二次规划问题的求解。

如上图所示: 距离超平面最近的几个训练样本点被称之为支持向量(support vector),两个异类支持向量到超平面的距离之和被称之为间隔。对应的SVM的基本型如下:

上述问题本身是一个凸二次规划问题,通过拉格朗日乘子法可得到其对偶问题。

上述两个公式非常重要,简直是核心公式。
得到上面的两个公式,再带回L中把去w和b消掉,得到如下公式:


从对偶问题解出的拉格朗日乘子对应着训练样本(xi,yi)。注意到上式中有不等式约束,因此上述过程需满足KKT条件,即要求

支持向量机有一个重要的性质,训练完成后,大部分的训练样本都不需要保留,最终模型仅与支持向量有关。
接下来就是如何求解这个二次规划问题,可使用通用的二次规划算法来求解,也可以利用问题本身的特性,采用SMO算法来求解。
上面是对SVM的理论做了极其简单的介绍,对支持向量机理论感兴趣的童鞋可以做进一步的研究。
二、车牌判别
opencv中对SVM进行了集成,调用opencv的SVM接口是十分方便的,对于定位的车牌区域,首先获取其车牌特征,这边采用的是LBP算子,具体内容上一节做了详细的介绍。SVM调用的类是opencv 机器学习模块中的SVM类,具体的代码如下所示:
typedef void (*svmCallback)(const cv::Mat& image, cv::Mat& features);
cv::Ptr<ml::SVM> svm_;
svmCallback extractFeature; PlateJudge::PlateJudge() {
svm_ = ml::SVM::load<ml::SVM>(kDefaultSvmPath);
extractFeature = getLBPFeatures;
} void PlateJudge::LoadModel(std::string path) {
if (path != std::string(kDefaultSvmPath)) {
if (!svm_->empty())
svm_->clear(); svm_ = ml::SVM::load<ml::SVM>(path);
}
} int PlateJudge::plateJudge(const Mat &inMat, int &result) {
Mat features;
extractFeature(inMat, features);
float response = svm_->predict(features);
result = (int)response; return ;
}
通过 SVM::load() 函数加载训练好的SVM参数文件,然后调用 predict()函数对当前区域进行判定,是否为车牌。
三、SVM训练
svm训练通过类SvmTrain 来进行,具体的训练函数如下所示:
void SvmTrain::train() {
svm_ = cv::ml::SVM::create();
svm_->setType(cv::ml::SVM::C_SVC);
svm_->setKernel(cv::ml::SVM::RBF);
svm_->setDegree(0.1);
svm_->setGamma(0.1);
svm_->setCoef0(0.1);
svm_->setC();
svm_->setNu(0.1);
svm_->setP(0.1);
svm_->setTermCriteria(cvTermCriteria(CV_TERMCRIT_ITER, , 0.0001));
auto train_data = tdata();
fprintf(stdout, ">> Training SVM model, please wait...\n");
long start = utils::getTimestamp();
svm_->train(train_data);
long end = utils::getTimestamp();
fprintf(stdout, ">> Training done. Time elapse: %ldms\n", end - start);
fprintf(stdout, ">> Saving model file...\n");
svm_->save(svm_xml_);
fprintf(stdout, ">> Your SVM Model was saved to %s\n", svm_xml_);
fprintf(stdout, ">> Testing...\n");
this->test();
}
kernel_type:SVM的内核类型(4种):
CvSVM::POLY : 多项式内核:-- polynomial: (gamma*u'*v + coef0)^degree
CvSVM::RBF : 高斯核-- radial basis function: exp(-gamma*|u-v|^2)
CvSVM::SIGMOID:Sigmoid函数内核-- sigmoid: tanh(gamma*u'*v + coef0)
svm_type:指定SVM的类型(5种):
1、CvSVM::C_SVC : C类支撑向量分类机。 n类分组 (n≥2),容许用异常值处罚因子C进行不完全分类。
2、CvSVM::NU_SVC :
类支撑向量分类机。n类似然不完全分类的分类器。参数为
庖代C(其值在区间【0,1】中,nu越大,决定计划鸿沟越腻滑)。
3、CvSVM::ONE_CLASS : 单分类器,所有的练习数据提取自同一个类里,然后SVM建树了一个分界线以分别该类在特点空间中所占区域和其它类在特点空间中所占区域。
4、CvSVM::EPS_SVR :
类支撑向量回归机。练习集中的特点向量和拟合出来的超平面的间隔须要小于p。异常值处罚因子C被采取。
5、CvSVM::NU_SVR :
类支撑向量回归机。
庖代了 p。
degree:内核函数(POLY)的参数degree。
gamma:内核函数(POLY/ RBF/ SIGMOID)的参数
。
coef0:内核函数(POLY/ SIGMOID)的参数coef0。
Cvalue:SVM类型(C_SVC/ EPS_SVR/ NU_SVR)的参数C。
nu:SVM类型(NU_SVC/ ONE_CLASS/ NU_SVR)的参数
。
p:SVM类型(EPS_SVR)的参数
。
class_weights:C_SVC中的可选权重,赋给指定的类,乘以C今后变成 class_weights*C 。所以这些权重影响不合类此外错误分类处罚项。权重越大,某一类此外误分类数据的处罚项就越大。
term_crit:SVM的迭代练习过程的中断前提,解决项目组受束缚二次最优题目。您可以指定的公差和或最大迭代次数。
对于训练数据 tdata()的获取,如下所示:
cv::Ptr<cv::ml::TrainData> SvmTrain::tdata() {
this->prepare();
cv::Mat samples;
std::vector<int> responses;
for (auto f : train_file_list_) {
auto image = cv::imread(f.file);
if (!image.data) {
fprintf(stdout, ">> Invalid image: %s ignore.\n", f.file.c_str());
continue;
}
cv::Mat feature;
getLBPFeatures(image, feature);
feature = feature.reshape(, );
samples.push_back(feature);
responses.push_back(int(f.label));
}
cv::Mat samples_, responses_;
samples.convertTo(samples_, CV_32FC1);
cv::Mat(responses).copyTo(responses_);
return cv::ml::TrainData::create(samples_, cv::ml::SampleTypes::ROW_SAMPLE,
responses_);
}
对于训练得到的结果,将保存在 svm_xml_文件中。
EasyPR源码剖析(7):车牌判断之SVM的更多相关文章
- EasyPR源码剖析(1):概述
EasyPR(Easy to do Plate Recognition)是本人在opencv学习过程中接触的一个开源的中文车牌识别系统,项目Git地址为https://github.com/liuru ...
- EasyPR源码剖析(6):车牌判断之LBP特征
一.LBP特征 LBP指局部二值模式,英文全称:Local Binary Pattern,是一种用来描述图像局部特征的算子,LBP特征具有灰度不变性和旋转不变性等显著优点. 原始的LBP算子定义在像素 ...
- EasyPR源码剖析(5):车牌定位之偏斜扭转
一.简介 通过颜色定位和Sobel算子定位可以计算出一个个的矩形区域,这些区域都是潜在车牌区域,但是在进行SVM判别是否是车牌之前,还需要进行一定的处理.主要是考虑到以下几个问题: 1.定位区域存在一 ...
- EasyPR源码剖析(3):车牌定位之颜色定位
一.简介 对车牌颜色进行识别,可能大部分人首先想到的是RGB模型, 但是此处RGB模型有一定的局限性,譬如蓝色,其值是255,还需要另外两个分量都为0,不然很有可能你得到的值是白色.黄色更麻烦,它是由 ...
- EasyPR源码剖析(4):车牌定位之Sobel算子定位
一.简介 sobel算子主要是用于获得数字图像的一阶梯度,常见的应用是边缘检测. Ⅰ.水平变化: 将 I 与一个奇数大小的内核进行卷积.比如,当内核大小为3时, 的计算结果为: Ⅱ.垂直变化: 将: ...
- EasyPR源码剖析(2):车牌定位
上一篇主要介绍了车牌识别的整体框架和流程,车牌识别主要划分为了两个过程:即车牌检测和字符识别,而车牌识别的核心环节就是这一节主要介绍的车牌定位,即 Plate Locate.车牌定位主要是将图片中有可 ...
- EasyPR源码剖析(8):字符分割
通过前面的学习,我们已经可以从图像中定位出车牌区域,并且通过SVM模型删除“虚假”车牌,下面我们需要对车牌检测步骤中获取到的车牌图像,进行光学字符识别(OCR),在进行光学字符识别之前,需要对车牌图块 ...
- EasyPR源码剖析(9):字符识别
在上一篇文章的介绍中,我们已经通过相应的字符分割方法,将车牌区域进行分割,得到7个分割字符图块,接下来要做的就是将字符图块放入训练好的神经网络模型,通过模型来预测每个图块所表示的具体字符.神经网络的介 ...
- jQuery之Deferred源码剖析
一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...
随机推荐
- [UnityShader基础]08.UI-Default.shader
参考链接: https://zhuanlan.zhihu.com/p/32561155 https://blog.csdn.net/WuShangLZ/article/details/80401441 ...
- py库:os、shutil、pathlib
https://www.cnblogs.com/MnCu8261/p/5494807.html shutil模块 http://blog.csdn.net/rozol/article/details/ ...
- 剑指offer——从上往下打印二叉树
题目描述:从上到下打印二叉树的节点,同一层的从左到右打印 思路:采用队列来存储单层的节点,然后通过删除队列的头结点操作,依次遍历每一层. 代码为: import java.util.ArrayList ...
- 折腾newifi3 d2笔记
1.忘记密码,恢复出厂 通电开机,等正常运行后,长按RESET大约6~8秒,见所有灯开始一起慢闪,可松手等重启就是出厂状态了,出厂IP是:192.168.99.1 2.免拆机刷breed 首先要打开s ...
- C#使用List实现类似RadioButtonGroup的单选功能
首先说说需求,有多种不同类型的UserControl用于以不同的方式显示数据,想通过在另一个view中实现某种点击选中按钮后,在数据显示view中,只让被逻辑关联的UserControl显示(Visi ...
- 【译】图解Transformer
目录 从宏观上看Transformer 把张量画出来 开始编码! 从宏观上看自注意力 自注意力的细节 自注意力的矩阵计算 "多头"自注意力 用位置编码表示序列的顺序 残差 解码器 ...
- vue 动态添加 <style> 样式 vue动态添加 绑定自定义字体样式
created(){ //动态添加自定义字体样式 let style = document.createElement('style'); style.type = "text/css&qu ...
- Multiple dex files define Lcom/google/gson/internal/Streams$AppendableWriter$CurrentWrite;
开发中引入第三方 aar 时编译同过,运行时出现问题: Multiple dex files define Lcom/google/gson/internal/Streams$AppendableWr ...
- python学习Day6 元组、字典、集合set三类数据用法、深浅拷贝
一.深浅拷贝 1. 值拷贝 ls1 = ls2 不开辟空间,指针跟着走.(直接将ls1中存放的地址拿过来,内存中不会开辟新的空间,所以你怎么变,我也跟着变.)(ls1内部的所有类型的值发生改变,l ...
- ARTS打卡计划第一周-Review
本周分享的文章来自于medium的 Testing Best Practices for Java + Spring Apps 这个文章主要讲的是java测试的一些最佳实践 1.避免函数返回void, ...