opencv学习笔记——自己训练人脸识别分类器

       在使用opencv自带的分类器haarcascade_frontalface_alt.xml进行人脸识别的基础认识后,决定自己训练一个分类器看一下效果。该过程大致可分为三个阶段:样本采集、分类器训练和运用训练好的分类器进行人脸检测。

1、样本的采集

       在训练前,我们需要进行正样本及负样本的采集。

       正样本采用的是ORL人脸数据库中的部分图像,本次共选用63张图像,初始图像大小为92*112,但在训练时出现了内存不足的问题,因此将其尺寸归一化为20*20。部分截图如下:

opencv学习笔记——自己训练人脸识别分类器

       负样本采用的是weizmann团队http://www.wisdom.weizmann.ac.il/~vision/Seg_Evaluation_DB/dl.html 网站上的图像分割数据库里面的灰色图像,总共200幅图片,大小大约在300*200像素,截图如下所示:

opencv学习笔记——自己训练人脸识别分类器

       图像采集完毕后,将其分别放在两个文件夹pos_img(正样本)和neg_img(负样本)下。再新建一个xml文件夹,xml文件夹存放后面训练过程中产生的数据模型,最后opencv会将其转换生成一个xml文件,也就是最终的分类器。

       然后,从OpenCv安装目录中查找出如下两个exe可执行文件:

opencv学习笔记——自己训练人脸识别分类器

opencv_createsamples.exe:用于创建样本描述文件,后缀名是.vec。专门为OpenCV训练准备,只有正样本需要,负样本不需要。 

opencv_haartraining.exe:是OpenCV自带的一个工具,封装了haar特征提取以及adaboost分类器训练过程。 

       一般来说,正负样本数目比例为1:3时训练结果较好,但是不是绝对。由于每个样本的差异性不同等因素,所以没有绝对的比例关系。但是负样本需要比正样本多,因为原则上说负样本的多样性越大越好,我们才能有效降低误检率,而不仅仅是通过正样本的训练让其能识别物体。在本次训练中,我选择了63个正样本和200个负样本,均为灰度图像。

       样本准备完毕后,打开Windows下的命令行窗口cmd,进入指定目录下。

opencv学习笔记——自己训练人脸识别分类器

在当前pos_img目录下生成一个pos.txt记录所有图片的名称。 

opencv学习笔记——自己训练人脸识别分类器

打开该txt文件,将pos.txt去掉,并将pgm 改为pgm 1 0 0 20 20。

opencv学习笔记——自己训练人脸识别分类器

这里1表示当前图片重复出现的次数是1, 0 0 20 20表示目标图片大小是矩形框从(0,0)到(20,20)。 

同理,进入neg_img目录,生成neg.txt,然后打开文件去掉neg.txt,其余不做改动。

opencv学习笔记——自己训练人脸识别分类器

opencv学习笔记——自己训练人脸识别分类器

结束后将pos.txt和neg.txt拷出,与opencv_createsamples.exe文件放在一个目录下:

opencv学习笔记——自己训练人脸识别分类器

2、使用opencv_createsamples.exe建立训练需要的参数列表

       Windows控制台进入指定目录下,我们之前已经在目录下放了opencv_createsamples.exe文件,在控制台下输入opencv_createsamples.exe可以得到各参数信息: 

opencv学习笔记——自己训练人脸识别分类器

在命令行窗口输入:

opencv学习笔记——自己训练人脸识别分类器

则在当前目录下,产生一个pos.vec文件。

opencv学习笔记——自己训练人脸识别分类器

指令介绍:

-vec pos.vec:指定生成的文件,最终生成的就是pos.vec; 
-info pos_img\pos.txt:目标图片描述文件,在pos\pos.txt; 
-bg neg_img\neg.txt:背景图片描述文件,在neg\neg.txt; 
-w 20:输出样本的宽度,20; 
-h 20:输出样本的高度,20; 

-num 63:要产生的正样本数量,63;

3、训练模型

       Windows控制台进入指定目录下,我们之前已经在目录下放了opencv_haartraining.exe文件,在控制台下输入opencv_haartraining.exe可以得到各参数信息: 

opencv学习笔记——自己训练人脸识别分类器

然后输入指令进行训练:

opencv学习笔记——自己训练人脸识别分类器

指令介绍:

-vec pos.vec:正样本文件名; 
-bg neg_img\neg.txt:背景描述文件; 
-data xml:指定存放训练好的分类器的路径名,也就是前面建立的xml文件夹; 
-w 20:样本图片宽度,20; 
-h 20:样本图片高度,20; 
-mem 1024:提供的以MB为单位的内存,很明显,这个值越大,提供的内存越多,运算也越快; 
-npos 45:取45个正样本,小于总正样本数; 
-neg 180:取180个负样本,小于总负样本数; 
-nstages 5:指定训练层数,层数越高耗时越长; 

-nsplits 5:分裂子节点数目, 默认值 为2;(本来设置为5 ,但训练时一直出差错,改为默认值后可正常训练)。

在这里-npos  -neg 两个参数若直接与正负样本总数相同,则在训练过程中会出现错误:训练中途,程序突然终止,提示"OpenCV Error: Assertion failed (elements_read == 1) in icvGetHaarTraininDataFromVecCallback, file ..\..\..\..\opencv\apps\haartraining\cvhaartraining.cpp, line 1861"。-npos的意思是每次训练从.vec文件中随机选取npos个正样本。由于存在虚警,在每一次训练一个强分类器之后,会把那些分类错误的从整个样本库中剔除掉,总的样本就剩下 CountVec = CountVec - (1 - minhitrate)* npos,在第二个强分类器的训练过程中就是从剩下的Countvec抽样,一直这样进行nstage次,所以就有CountVec >= (npos + (nstages - 1)*(1 -minhitrate) * npos ) + nneg 。当把npos设置与vec中总样本数相同时,第二个强分类器训练时,必然就会报错,提示样本数不足。只要将取值改小即可。

接下来要做的就是等待训练结束:

opencv学习笔记——自己训练人脸识别分类器

opencv学习笔记——自己训练人脸识别分类器

训练过程参数解释:

opencv学习笔记——自己训练人脸识别分类器

N:层数  %
SMP:样本的使用率 
F : +表示通过翻转,否则是-
ST.THR : 分类器的阈值 
HR:当前分类器 对正样本识别正确的概率
FA:当前分类器 对负样本识别错误的概率

EXP.ERR : 分类器的期望错误率

训练结束后会在根目录下生成xml.xml文件,在xml文件夹下生成最终的分类器:

opencv学习笔记——自己训练人脸识别分类器

opencv学习笔记——自己训练人脸识别分类器

4、测试

       用自己训练的分类器替换opencv自带的分类器进行人脸识别:

opencv学习笔记——自己训练人脸识别分类器opencv学习笔记——自己训练人脸识别分类器

因为训练的样本过少,分类器的层数也不多,分类效果并不好,还有待提高。