前言
使用opencv自带的分类器效果并不是很好,由此想要训练自己的分类器,正好opencv有自带的工具进行训练。本文就对此进行展开。
步骤
1.查找工具文件;
2.准备样本数据;
3.训练分类器;
具体操作
注意,本文是在windows系统实现的,当然也可以在linux系统进行。
1.查找工具文件;
opencv中的自带的分类器训练工具在开源库中以应用程序的类型呈现的,具体目录如下。
.\opencv2410\build\x64\vc12\bin
可以在该目录下查找到相关的工具文件,有opencv_createsamples、opencv_haartraining、opencv_performance、opencv_traincascade;
其中,opencv_haartraining和opencv_traincascade是opencv开源库用于训练级联分类器的两个程序。opencv_traincascade是一个较新的程序,使用OpenCV2.x API以c++编写,二者的主要区别是opencv_traincascade支持Haar和LBP两种特征,并易于增加其他特征。与Haar特征相比,LBP特征是整数特征,因此训练和检测过程都会比Haar特征快几倍。LBP和Haar特征用于检测的准确率是依赖训练过程中训练数据的质量和训练参数。训练一个与基于Haar特征同样准确度的LBP的分类器是可能的。
另外,opencv_traincascade和opencv_haartraining两个训练程序的输入参数有些微的差别,比如前者是numPos和numNeg,而后者是npos和nneg,同时二者所输出的分类器的文件格式也并不相同,注意区分。新的级联检测器接口(object模块中的CascadeClassifier类)支持这两种格式。opencv_traincascade可以旧格式导出训练好的级联分类器,但是在训练过程被中断后再重启训练过程时,二者不能装载和中断前不同的文件格式。另外,opencv_traincascade程序使用TBB(Threading Building Blocks)来处理多线程,如果希望使用多核并行运算加速,请使用TBB来编译opencv。
opencv_createsamples用来准备用于训练的正样本数据和测试数据,能够生成新旧两个训练程序支持的正样本数据。输出为以*.vec为扩展名的文件,该文件以二进制方式存储图像。
opencv_performance可以用来评估分类器的质量,但是只能评估opencv_haartraining输出的分类器。它读入一组标注好的图像,运行分类器并报告性能。
2.准备样本数据;
训练需要一些样本数据,分别是正样本和负样本。负样本是指不包括目标的图像,正样本是只包含待检测目标的图像。负样本必须手工准备,而原始正样本可以使用opencv_createsamples创建训练器需要的正样本图像。样本图像可以是不同尺寸的,但是不能小于训练窗口的大小。
2.1样本数据要求;
正样本原始图像应该包含要检测的目标对象,比如人脸或者其他,而负样本图像不能包含要检测的目标。正样本图像的背景需要多样化,可以尝试用随机噪点填充背景,避免固定的背景。目标的像素数量肯定要多于背景像素数量的,原始正样本图像尺寸可以不同,但是应该有相同的高宽比。正负样本的格式、尺寸、通道数目可以不同,但是要保证尺寸不能小于训练的参数(即生成vec文件时输入的-w-h参数)。负样本不能包含目标,且应该多样化。正负样本的数目和比例的选取依赖于检测任务,建议在1:2-1:3之间,但这不是硬性规定的。建议开始使用小数目的样例生成级联器然后进行测试,如果效果不佳就可以增加正负样本数量。
2.2生成负样本描述文件;
负样本here(xte1);
在工程目录下,创建一个文件夹用于存放负样本图像,可以不同尺寸、不同通道数、不同格式,但尺寸不能小于正样本训练参数。负样本要尽量多样化,且不能包含要检测的目标对象。
负样本目录结构
/negimg
img1.jpg
img2.bmp
negimg.txt
其中,negimg.txt是负样本的描述文件,
E:\work\facedet\facedet-train\negall\GULF_99.bmp E:\work\facedet\facedet-train\negall\u=1000618073,567507844&fm=23&gp=0.jpg E:\work\facedet\facedet-train\negall\u=1000795684,2512483114&fm=23&gp=0.jpg
生成方式是在图像目录下新建批量生成文件negimg.bat,双击即可;
dir /b/s/p/w *.bmp > num.txt
注意,1)不同的图像格式; 2)避免空行,将最后一行的空行删除;
2.3生成正样本描述文件*.vec;
2.3.1 创建文件夹的过程和负样本基本一样,此处不再赘述。生成正样本描述文件之后,打开描述文件,将jpg全部替换成jpg 1 0 0 20 20,其中jpg是图像格式,1表示对应图像中检测目标数目,[0 0 20 20]表示对应图像中目标位置分别是[left top width height];注意可以有多个目标,不同图像对应的目标数目和位置可能不同,可能需要分别处理;可以使用相对路径,也可以是绝对路径。
正样本描述文件将每张图像上的目标数目,以及每个目标对象的位置信息进行描述,按照以下格式描述。本质上讲,正样本描述文件是用来加速机器学习的。
positive_image_name num_of_objects x y width height x y width height …
如果一张图像有多个目标,则文件内容为
img/img_with_faces_1.jpg 1 140 100 45 45 img/img_with_faces_2.jpg 2 100 200 50 50 50 30 25 25
2.3.2 生成*.vec正样本描述文件;
这个时候就要使用opencv_createsample生成vec文件啦!训练图像正样本目标尺寸的高宽参数一般设置为20*20或者24*24,本文设置为20*20.
opencv_createsamples.exe -vec pos.vec -info posimg.txt -num 7767 -w 20 -h 20
-vec是输出文件,内含用于训练的正样本;-info是描述目标所在图像及大小位置的描述文件;-num是生成正样本的数目(应该是所有图像中的目标数目吧?);
-w和-h是输出样本的目标尺寸,以像素为单位;
3.训练分类器;
3.1 本文使用opencv_traincascade训练一个级联分类器。现在正负样本、正负样本描述文件都已准备好,开始进行训练,只需要设置想要的参数即可;
opencv_traincascade.exe -data xml -vec posall.vec -bg negall.txt -numPos 1000 -numNeg 2500 -mem 500 -mode ALL -w 20 -h 20
其中,xml是存放训练结果的目录;注意,参数-w和-h应该与在生成.vec文件时候设置的-w和-h保持一致,同时写在-numPos和-numNeg的正负样本图像应该都是真正可用的,可打开的。各个参数的意义可参考here,有通用参数、级联参数、Boosted分类器参数、类Haar特征参数、LBP参数;
-
通用参数:
-
-data <cascade_dir_name>
目录名,如不存在训练程序会创建它,用于存放训练好的分类器。
-
-vec <vec_file_name>
包含正样本的vec文件名(由 opencv_createsamples 程序生成)。
-
-bg <background_file_name>
背景描述文件,也就是包含负样本文件名的那个描述文件。
-
-numPos <number_of_positive_samples>
每级分类器训练时所用的正样本数目。要小于正样本总数。
-
-numNeg <number_of_negative_samples>
每级分类器训练时所用的负样本数目,可以大于 -bg 指定的图片数目。可以大于负样本总数。
-
-numStages <number_of_stages>
训练的分类器的级数。一般取值15-25。
-
-precalcValBufSize <precalculated_vals_buffer_size_in_Mb>
缓存大小,用于存储预先计算的特征值(feature values),单位为MB。
-
-precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb>
缓存大小,用于存储预先计算的特征索引(feature indices),单位为MB。内存越大,训练时间越短。
-
-baseFormatSave
这个参数仅在使用Haar特征时有效。如果指定这个参数,那么级联分类器将以老的格式存储。
-
-
级联参数:
-
-stageType <BOOST(default)>
级别(stage)参数。目前只支持将BOOST分类器作为级别的类型。
-
-featureType<{HAAR(default), LBP}>
特征的类型: HAAR - 类Haar特征; LBP - 局部纹理模式特征。
-
-w <sampleWidth>
-
-h <sampleHeight>
训练样本的尺寸(单位为像素)。必须跟训练样本创建(使用 opencv_createsamples 程序创建)时的尺寸保持一致。
-
-
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。一般取值0.95-0.995。
-
-maxFalseAlarmRate <max_false_alarm_rate>
分类器的每一级希望得到的最大误检率。总的误检率大约为 max_false_alarm_rate^number_of_stages.一般取值0.4-0.5。
-
-weightTrimRate <weight_trim_rate>
Specifies whether trimming should be used and its weight. 一个还不错的数值是0.95。
-
-maxDepth <max_depth_of_weak_tree>
弱分类器树最大的深度。一个还不错的数值是1,是二叉树(stumps)。
-
-maxWeakCount <max_weak_tree_count>
每一级中的弱分类器的最大数目。The boosted classifier (stage) will have so many weak trees (<=maxWeakCount), as needed to achieve the given -maxFalseAlarmRate.
-
-
类Haar特征参数:
-
-mode <BASIC (default) | CORE | ALL>
选择训练过程中使用的Haar特征的类型。 BASIC 只使用右上特征, ALL 使用所有右上特征和45度旋转特征。
-
-
LBP特征参数:
LBP特征无参数。
训练完成之后,打开保存-data对应目录,即可看到训练结果。cascade.xml文件即为最终的训练结果,可以用来进行目标检测。
3.2训练过程相关问题;
问题1:
Train dataset for temp stage can not be filled. Branch training terminated.
原因:训练数据在中间训练阶段没有filled,训练分支被终止。此时可以生成cascade.xml文件,终止的原因是训练数据不足,一般已经训练了多个stage。
还有一个原因可能是图像数据的路径有问题,这种情况一般stage0即出现错误。
问题2:
Required leaf false alarm rate achieved. Branch training terminated
原因:负样本数据中包含要检测的目标对象,导致错误预警率过高。此时可以检查正负训练样本数据,是否有误。
接下来就要测试训练的模型能否得到较好的检测效果,请参看here。
参考
1.opencv人脸检测训练分类器及其常见问题-译文-Good;
3.人脸检测训练心得;
4.opencv_traincascade支持Haar和LBP特征;
6.如何使用工具进行训练;
7.如何训练详解;
9.opencv官网-原文;
10.模型训练简介;
完