opencv提高之cascade分类器训练人脸检测模型

时间:2020-12-20 04:13:27

1.概述

首先澄清一个概念:人脸检测是要检测图像中有没有人脸,人脸识别是要检测出图像中的人脸是谁

在opencv中有两个类型的分类器:opencv_haartraining和opencv_traincascade,后者是2.x版本中基于C++写的新版本的分类器。二者最主要的区别是opencv_traincascade支持Haar和LBP。LBP在训练和检测方面要比Haar特征快数倍。Haar和LBP的检测质量取决于要训练的数据和训练的参数设置。
opencv_traincascade与opencv_haartraining以不同的文件类型存储训练分类器。新的cascade检测接口支持者两种格式。opencv_traincascade可以保存(输出)旧格式的级联器,但是opencv_traincascade和opencv_haartraining不能在训练中断后加载另一种格式的分类器。
需要注意的是opencv_traincascade可使TBB用于多线程,而使用多核心的opencv一定是基于TBB。

opencv_createsamples:用于准备训练数据的正样本和测试样本。opencv_createsamples可以生成支持opencv_haartraining和opencv_traincascade分类器的正样本数据。输出文件是以.vec为后缀的包含图像信息的二进制数据类型。

opencv_performance:可以用来评估分类器的质量。但仅对opencv_haartraining生成的分类器有效。它需要一个被标记的图像集合,运行分类器,报告运行过程中找到目标的数量、丢失目标数量、误报警数量和其他信息。
在其官方文档中提到opencv_haartraining已经是一个过时的应用,而opencv_traincascade将会得到进一步发展。

Windows中两个.exe文件位于..\opencv\build\x64\vc12\bin中,如果是32位则把路径中x64改为x86即可;Linux版本两个应用程序位于/usr/local/bin文件夹中。找到两个应用拷贝到样本所在的文件夹。
opencv提高之cascade分类器训练人脸检测模型
opencv提高之cascade分类器训练人脸检测模型

2.样本

2.1样本准备

样本训练需要正负样本。负样本和目标图像没有任何关系,正样本是与检测目标相关的图像。

2.2负样本

负样本是不包含检测目标的任意图像。负样本在一个特殊的文件中被枚举,每一行包含一张图片的名称。这个文件必须手动生成。应该注意到负样本和样本图片也被称为背景样本或背景样本图片。这些描述图片尺寸大小可以不同,单是一定要大于训练窗口尺寸,因为这些图片会按照训练尺寸进行二次抽样。

描述文件例子:

/img
img1.jpg
img2.jpg
bg.txt

也就是说在img的文件夹中有若干图片样本img1.jpg、img2.jpg,生成的描述文件bg.txt格式如下:

img/img1.jpg
img/img2.jpg

针对不同的OS版本分别给出方案:
Linux-Ubuntu
打开终端,输入如下命令

ls ./neg/*.*>neg.txt

运行后在cascade文件夹下会多出一个名字为neg.txt的文件,打开会看到包含图像的名称和路径,如下opencv提高之cascade分类器训练人脸检测模型

Windows
打开cmd命令,进入样本所在文件夹,然后执行

dir /b >neg.txt

在负样本文件夹下出现neg.txt文件,打开删除文本neg.txt
opencv提高之cascade分类器训练人脸检测模型
利用查找替换操作,给文件名加上相对路径,如下:
opencv提高之cascade分类器训练人脸检测模型
完成后将neg.txt剪切到上一层文件目录下即与neg、pos等文件相同目录

至此负样本准备工作完成

2.3正样本
正样本是通过opencv_createsamples从单张张目标图片或一些实现标识图片创建,需要注意的是训练正样本模型需要大量的图像数据支持,如果是一种刚性的图片如OpenCV的Logo,识别这种图像看似只有一个正样本图像,但是我们可以通过旋转Logo、调整光照等各种方式来得到大量的样本进行下一步的训练。样本数量和范围的随机性可以通过OpenCV_createsamples来控制,其命令行参数如下:

-vec<vec_file_name>
包含训练正样本数据的输出文件名
-img<img_file_name>
源目标图像(如一个公司logo)
-bg<background_file_name>
负样本描述文件,包含一个用作背景的随机负样本图片列表
-num<number_of_samples>
正样本数量
-bgcolor<background_color>
背景色(假定当前是灰度图),背景色预置为透明色,对于压缩图片,颜色方差由bgthresh参数来指定,所有像素在bgcolor-bgthresh和bgcolor+bgthresh范围内都是透明的
-bgthresh<background_color_threshold>
背景色阈值
-inv
如果指定,颜色会反色
-randinv
如果指定,颜色会反色,颜色随机
-maxidev<max_intensity_deviation>
前置样本(foreground samples)像素最大偏离差,我的理解就是要训练的图像中物体像素的最大偏差
-maxxangle<max_x_rotation_angle>
-maxyangle<max_y_rotation_angle>
-maxzangle<max_z_rotation_angle>
三个方向最大旋转角度,以弧度为单位
-show
很有用的debugging选项。如果指定每个样本会被现实出来,"ESC"会关闭这一功能,即不显示样本图片而样本创建会继续进行。
-w<sample_width>
输出样本的宽(以像素为单位)
-h<sample_height>
输出样本的高(以像素为单位)
-pngoutput
这个选项是打开opencv_createsamples工具创建一个PNG类型的样本和一系列注释类型文件来替代一个矢量vec文件

正样本描述文件如下:

/img
img1.jpg
img2.jpg
info.dat

也就是说在img的文件夹中有若干图片样本img1.jpg、img2.jpg,生成的描述文件info.dat格式如下

img/img1.jpg 1 140 100 45 45
img/img2.jpg 2 100 200 50 50 50 30 25 25

img1.jpg后面参数是其生成矩形边界(140 100 45 45)对应(x,y,width,height),img2.jpg包含两个目标实例。为了能够从集合中创建正样本,-info参数在指定时需用-img代替:
-info
标记图像的文件集合
在生成vec描述文件时,图像不失真,只有-w、-h、-show和-num等参数对文件有影响。
使用opencv_createsamples程序生成正样本描述文件时,只有-vec、-w、-h等参数是需要被指定的。

Linux-Ubuntu
命令与负样本类似,如下:

ls ./pos/*.*>pos.dat

打开pos.dat文件将利用查找替换操作将文件名归一化为如下形式:
opencv提高之cascade分类器训练人脸检测模型
保存,之后执行如下命令生成.vec文件

opencv_createsamples -vec pos.vec -info pos.dat -bg neg.txt -w 20 -h 20

需要注意的是命令行中文件w h的值必须与上面归一化中设置的尺寸相同。如下:
opencv提高之cascade分类器训练人脸检测模型
文件夹中多了一个pos.vec,这时针对Linux系统中的正样本就已经准备好了。

Windows
打开cmd命令,进入样本所在文件夹,然后执行

dir /b >pos.dat

打开文件删除行pos.dat,然后对文件进行归一化如下:
opencv提高之cascade分类器训练人脸检测模型
保存,然后将pos.dat剪切到上层目录下即与neg、pos等文件相同目录,执行如下命令:

opencv_createsamples.exe -vec pos.vec -info pos.dat -bg neg.txt -w 20 -h 20

生成pos.vec文件,至此针对Windows下正样本就已经准备就绪

3.cascade training

上面样本准备好之后就可以进行分类器训练了,前面提到过opencv提供了opencv_haartraining和opencv_traincascade两种方式来训练一个cascade分类器,但只有最新的opencv_traincascade会被长期支持。其参数命令如下:
常用命令行

-data<cascade_dir_name>
训练的分类器存储文件夹
-vec<vec_file_name>
包含正样本的vec文件(由opencv_cratesamples创建)
-bg<background_file_name>
背景描述文件
-numPos<number_of_positive_samples>
-numNeg<number_of_negative_samples>
用于每个分类器训练层级的正负样本数量
-numStages<number_of_stages>
用于训练分类器的级(stage)数
-precalcValBufSize<precalculated_vals_buffer_size_in_Mb>
缓存大小,用于存储预先计算的特征点值(单位为:Mb)
-precalcIdxBufSize<precalculated_idxs_buffer_size_in_Mb>
缓存大小,用于存储预先计算的特征索引,单位为Mb,分配空间越大,训练就越快
-baseFormatSave
这个参数在使用Haar特征时有效,如果指定这个参数,级联分类器将以老的格式存储训练数据。
-acceptanceRatioBreakValue
这个参数是用来指定你的训练学习的精度和什么时候结束。一个好的指导方针是精度最好不好大于10e-5,以防止会重复训练已经训练过的数据。默认值是-1来忽视这个特征。

cascade 参数

-stageType<BOOST(default)>
级别类型,目前只支持BOOST类型
-featureType<{HAAR(default),LBP}>
特征类型:HAAR-类HAAR特征;LBP-局部纹理模式特征
-w<sampleWidth>
-h<sampleHeight>
正样本的尺寸(单位:像素).必须跟训练样本创建时的尺寸一致

Boosted分类器参数

-bt<{DAB,RAB,LB,GAB(default)}>
boosted分类器的类型:DAB-Discrete AdaBoost,RAB-Real AdaBoost,LB-LogitBoost,GAB-Gentle AdaBoost
-minHitRate<min_hit_rate>
分类器的每一级希望得到最小检测率(即正样本被判断有效的比例),总的检测率大约为min_hit_rate^number_of_stages
-maxFalseAlarmRate<max_false_alarm_rate>
分类器的每一级希望的最大误检率(负样本判定为正样本的概率)总的误判率为max_false_alarm_rate^number_of_stages
-weightTrimRate<weight_trim_rate>
指定是否使用图像裁剪并指定其裁剪权重,典型值是0.95
-maxDepth<max_depth_of_weak_tree>
弱分类器数的最大深度,典型值是1,代表二叉树
-maxWeakCount<max_weak_tree_count>
每一级中弱分类器的最大数目,强分类器中包含很多弱的树(<maxWeakCount)来实现设定的最大误检率。

Haar-like特征参数

-mode<BASIC(default)|CORE|ALL>
选择训练中使用的Haar特征类型。BASIC只使用右上特征,ALL使用所有右上特征及45度旋转特征。

Linux-Ubuntu
在文件夹中新建data文件夹,执行如下命令

opencv_traincascade -data data -vec pos.vec -bg neg.txt -numPos 100 -numNeg 200 -numStages 20 -w 20 -h 20 -minHitRate 0.9999 -maxFalseAlarmRate 0.5 -mode ALL

然后训练开始:

opencv提高之cascade分类器训练人脸检测模型

Windows
新建data文件夹,执行如下命令:

opencv_traincascade.exe -data data -vec pos.vec -bg neg.txt -numPos 100 -numNeg 200 -numStages 20 -w 20 -h 20 -minHitRate 0.9999 -maxFalseAlarmRate 0.5 -mode ALL

训练开始

opencv提高之cascade分类器训练人脸检测模型

注意
上面的正负样本参数是我手头有的,样本容量太少,层级用20只能训练到16级