C++ OpenCV SVM实战Kindle检测(一)----训练数据

最近也是在接触机器学习,通过做了几个MLNET的例子对机器学习有了一点了解,OpenCV中也有机器学习这块,所以我们就直接来用Kindle做一个实战。

视频演示效果

上面的视频已经看到,是了我们通用OpenCV的SVM训练后检测到的Kindle效果,整个SVM的介绍我们将分为两章,本章是简单介绍一下SVM和对Kindle的训练生成训练文件,下一篇我们主要是就看看怎么做预测显示标记出来,预测篇我们重新用一个新的视频来看看检测Kindle的效果。

也是在两篇都介绍完后,按照惯例,我也会把源码发布出来。

SVM简介

SVM较其他传统机器学习算法的优点:

1、小样本,SVM算法要求的样本数是相对比较少的。SVM解决问题的时候,和样本的维数是无关。

2、结构风险最小。(对问题真实模型的逼近与问题真实解之间的误差,就叫做风险,更严格的说,误差的累积叫做风险)。

3、非线性,是指SVM擅长应付样本数据线性不可分的情况,主要通过松弛变量(也有人叫惩罚变量)和核函数技术来实现,这一部分是SVM的精髓。

OpenCV SVM的核函数: 线性核函数:SVM::LINEAR,线性内核,没有高维空间映射,速度快; 多项式核函数:SVM::POLY,gamma>0,coef(),degree; 径向基核函数: SVM::RBF,比较好的选择,gamma>0; SIGMOD核函数:这个核让人想起神经网络和深度学习。。gamma,coef();

样本训练代码实现

核心函数

hog_deal

void hog_deal(cv::Mat& src, std::vector<float>& dst)
{
//定义Hog,输入图像必须能被2整除
cv::HOGDescriptor hog;
//获取默认的值 64 * 128
int imgwidth = hog.winSize.width;
int imgheight = hog.winSize.height;


int h = src.rows;
int w = src.cols;
float rate = (float)imgwidth / w;


cv::Mat tmpsrc, gray;
//变换图像为64 * 128的大小
cv::resize(src, tmpsrc, cv::Size(imgwidth, int(rate*h)));
//灰度转换
cv::cvtColor(tmpsrc, gray, cv::COLOR_BGR2GRAY);


//为了保证源图的比例,如果图片大于64*128,就截取roi区域
//如果小于64*128就填充,保证图片信息不会丢失
cv::Mat result = cv::Mat::zeros(cv::Size(imgwidth, imgheight), CV_8UC1);
//新建Mat填充127灰度
result = cvScalar(127);
cv::Rect roi;
roi.x = 0;
roi.width = imgwidth;
roi.y = (imgheight - gray.rows) / 2;
roi.height = gray.rows;


gray.copyTo(result(roi));
//计算描述子,一般窗口步长都用Size(8,8)就是8*8
hog.compute(result, dst, cv::Size(8, 8), cv::Size(0, 0));
}

01

创建项目

我们新建了一个opencv-svmtrain的项目,设置可以参见《VS2017配置OpenCV通用属性》。

然后定义一下训练生成的文件地址,还有取训练数据正向样本和负向样卡的路径。

正向样本

可以看到我拍了不少的Kindle图在里面。

负向样本

负向样本的图片基本都是北景图,反正是都不要带Kindle的就可以了。

02

定义训练数据

通过读取正向和负向数据的地址,计算出总共的图片数来定义我们的训练数据Mat。

划重点

本段说明摘自网络

首先要有一个整体的认识,每一个目标都对应一个一维特征向量,这个向量一共有n维,这个n不是凭空瞎猜的,是有理有据,打个比方,为什么opencv自带的hog检测子是3781维的?这个问题在初期确实比较头疼,纠结了好长的时间,不过别着急,先来看一下opencv里的HOGDescriptor这个结构的构造函数HOGDescriptor(Size winSize, Size blocksize, Size blockStride, Size cellSize, ...(后面的参数在这里用不到)),去查一下opencv默认的参数我们可以看 到,winSize(64, 128),blockSize(16, 16),blockStride(8, 8),cellSize(8, 8),很显然hog 是将一个特征窗口win划分为很多的块block,在每一个块里又划分为很多的细胞单元cell(即胞元),hog特征向量既是把这些所有的cell对应 的小特征串起来得到一个高维的特征向量,那么这个窗口对应的一维特征向量维数n就等于窗口中的块数 x 块中的胞元数 x 每一个胞元对应的特征向量数。写到这里,窗口中的块数 x 块中的胞元数 x 每一个胞元对应的特征向量数, 带入看一下n = 105x4x9 = 3780, 这就是这个窗口对应的特征了。有人会说,为什么opencv里的getDefaultPeopleDetector()得到的是3781维呢?这是因为另外一维是一维偏移,(很崩溃是吧,我也崩溃很久。。。,下一段解释)。我们利用hog + svm检测行人,最终的检测方法是最基本的线性判别函 数,wx + b = 0, 刚才所求的3780维向量其实就是w,而加了一维的b就形成了opencv默认的3781维检测算子, 而检测分为train和test两部分,在 train期间我们需要提取一些列训练样本的hog特征使用svm训练最终的目的是为了得到我们检测的w以及b,在test期间提取待检测目标的hog特征x,带入方程是不是就能进行判别了呢?

上面这段话其实也是对我们文章前面写的核心函数hog_deal的一个说明。

02

处理正向和负向数据

遍历目录后,读取每一张图片,通过我们的hog_deal来计算Hog的描述子,然后在放到labels里面,负向数据也是这样做,不同点是最后一句:

labels.at<float>(i,0)=1; //正向

labels.at<float>(i,0)=-1; //负向

03

训练数据并保存文件

划重点

SVM类型

01

C_SVC : C类支撑向量分类机。n类分组 (n≥2),容许用异常值处罚因子C进行不完全分类。

02

NU_SVC : 类支撑向量分类机。n类似然不完全分类的分类器。参数为gamma代替C。

03

ONE_CLASS : 单分类器,所有的练习数据提取自同一个类里,然后SVM建树了一个分界线以分别该类在特点空间中所占区域和其它类在特点空间中所占区域。

04

EPS_SVR : 用于回归。练习集中的特征向量和拟合出来的超平面的间隔须要小于p。异常值处罚因子C被采取。

05

NU_SVR : 回归机,gamma代替p。

程序运行截图

从上图中我们看到,先加载图片后再进行训练,训练完后将训练的数据存放到了我们设置的训练文件中,如下:

下一篇我们就来看看怎么检测识别结果,并把程序的源码传上来,敬请期待。。。。

-END-

原文发布于微信公众号 - 微卡智享(VaccaeShare)

原文发表时间:2019-10-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券