opencv_createsamples -info pos.txt -vec pos.vec -bg neg.txt -w 20 -h 20 -num 2706
opencv_traincascade.exe -data xml -vec pos.vec -bg neg.txt -numPos 1000 -numNeg 2000 -numStages 6 -precalcValbufSize 200 -precalcdxBufSize 1000 -featureType LBP -w 20 -h 20
首先,需要说明的是,OpenCV自带的haar training提取的特征是haar特征(具体请参考我的另一篇关于haar特征的文章:http://blog.csdn.net/carson2005/article/details/8094699 ),分类器是AdaBoost级联分类器(如需了解Adaboost算法,请参考我的另一篇文章:http://blog.csdn.net/carson2005/article/details/8130557 )。所谓的级联分类器,就是将若干的简单的分量分类器(可以理解为一般的普通分类器)依次串联起来,最终的检测分类结果,要依次通过所有的分量分类器才能算是一个有效的检测分类结果。否则,就认为当前检测区域内没有我们需要找的目标。
利用OpenCV自带的haar training程序训练一个分类器,需要经过以下几个步骤:
(1)收集训练样本:
训练样本包括正样本和负样本。正样本,通俗点说,就是图片中只有你需要的目标。而负样本的图片只要其中不含有目标就可以了。但需要说明的是,负样本也并非随便选取的。例如,你需要检测的目标是汽车,那么正样本就应该是仅仅含有汽车的图片,而负样本显然不能是一些包含天空的,海洋的,风景的图片。因为你最终训练分类器的目的是检测汽车,而汽车应该出现在马路上。也就是说,分类器最终检测的图片应该是那些包含马路,交通标志,建筑物,广告牌,汽车,摩托车,三轮车,行人,自行车等在内的图片。很明显,这里的负样本应该是包含摩托车、三轮车、自行车、行人、路面、灌木丛、花草、交通标志、广告牌等。
另外,需要提醒的是,adaboost方法也是机器学习中的一个经典算法,而机器学习算法的前提条件是,测试样本和训练样本独立同分布。所谓的独立同分布,可以简单理解为:训练样本要和最终的应用场合非常接近或者一致。否则,基于机器学习的算法并不能保证算法的有效性。此外,足够的训练样本(至少得几千张正样本、几千张负样本)也是保证训练算法有效性的一个前提条件。
这里,假设所有的正样本都放在f:/pos文件夹下,所有的负样本都放在f:/neg文件夹下;
(2)对所有的正样本进行尺寸归一化:
上一步收集到的正样本,有很多的尺寸大小,有的是200*300,有的是500*800...尺寸归一化的目的,就是把所有的图片都缩放到同一大小。比如,都缩放到50*60的大小。
(3)生成正样本描述文件:
所谓的正样本描述文件,其实就是一个文本文件,只不过,很多人喜欢将这个文件的后缀改成.dat而已。正样本描述文件中的内容包括:文件名 目标个数 目标在图片中的位置(x,y,width,height)
典型的正样本描述文件如下所示:
0.jpg 1 0 0 30 40
1.jpg 1 0 0 30 40
2.jpg 1 0 0 30 40
.....
不难发现,正样本描述文件中,每一个正样本占一行,每一行以正样本图片开头,后面紧跟着该图片中正样本的数量(通常为1),以及正样本在图片中的位置
假如,f:\pos文件夹下有5000个正样本图片,每个图片中仅有一个目标。那么,我们可以写程序(遍历文件夹中的所有图片文件,将文件名写入到文件中,将正样本在图片中的位置,大小都写入文件中)生成一个pos.dat文件作为正样本描述文件。
(4)创建正样本vec文件
由于haarTraining训练的时候需要输入的正样本是vec文件,所以需要使用createsamples程序来将正样本转换为vec文件。
打开OpenCV安装目录下bin文件夹里面的名为createSamples(新版本的OpenCV里面改名为opencv_createSamples)的可执行程序。需要提醒的是,该程序应该通过命令行启动(可以参考我的另一篇博客:http://blog.csdn.net/carson2005/article/details/6704589 )。并设置正样本所在的路径以及生成的正样本文件保存路劲(例如:f:\pos\pos.vec)。
Createsamples程序的命令行参数:
命令行参数:
-vec <vec_file_name>
训练好的正样本的输出文件名。
-img<image_file_name>
源目标图片(例如:一个公司图标)
-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>
背景色最大的偏离度。
-maxangel<max_x_rotation_angle>
-maxangle<max_y_rotation_angle>,
-maxzangle<max_x_rotation_angle>
最大旋转角度,以弧度为单位。
-show
如果指定,每个样本会被显示出来,按下"esc"会关闭这一开关,即不显示样本图片,而创建过程继续。这是个有用的debug选项。
-w<sample_width>
输出样本的宽度(以像素为单位)
-h《sample_height》
输出样本的高度,以像素为单位。
(5) 创建负样本描述文件
在保存负样本的文件夹下生成一个负样本描述文件,具体步骤同(3),此处不再赘叙;
(6)进行样本训练
该步骤通过调用OpenCV\bin目录下的haartraining程序(新版本的opencv改名为opencv_haartraining)来完成。其中,Haartraining的命令行参数为:
-data<dir_name>
存放训练好的分类器的路径名。
-vec<vec_file_name>
正样本文件名(由trainingssamples程序或者由其他的方法创建的)
-bg<background_file_name>
背景描述文件。
-npos<number_of_positive_samples>,
-nneg<number_of_negative_samples>
用来训练每一个分类器阶段的正/负样本。合理的值是:nPos = 7000;nNeg = 3000
-nstages<number_of_stages>
训练的级联分类器层数。
-nsplits<number_of_splits>
决定用于阶段分类器的弱分类器。如果1,则一个简单的stump classifier被使用。如果是2或者更多,则带有number_of_splits个内部节点的CART分类器被使用。
-mem<memory_in_MB>
预先计算的以MB为单位的可用内存。内存越大则训练的速度越快。
-sym(default)
-nonsym
指定训练的目标对象是否垂直对称。垂直对称提高目标的训练速度。例如,正面部是垂直对称的。
-minhitrate《min_hit_rate》
每个阶段分类器需要的最小的命中率。总的命中率为min_hit_rate的number_of_stages次方。
-maxfalsealarm<max_false_alarm_rate>
没有阶段分类器的最大错误报警率。总的错误警告率为max_false_alarm_rate的number_of_stages次方。
-weighttrimming<weight_trimming>
指定是否使用权修正和使用多大的权修正。一个基本的选择是0.9
-eqw
-mode<basic(default)|core|all>
选择用来训练的haar特征集的种类。basic仅仅使用垂直特征。all使用垂直和45度角旋转特征。
-w《sample_width》
-h《sample_height》
训练样本的尺寸,(以像素为单位)。必须和训练样本创建的尺寸相同。
一个训练分类器的例子:
"D:\Program Files\OpenCV\bin\haartraining.exe" -data data\cascade -vec data\pos.vec -bg negdata\negdata.dat -npos 49 -nneg 49 -mem 200 -mode ALL -w 20 -h 20
训练结束后,会在目录data下生成一些子目录,即为训练好的分类器。
(7) 生成xml文件
上一步在进行haartraining的时候,会在data目录下生成一些目录及txt文件,我们需要调用opencv\bin\haarconv.exe将这些txt文件转换为xml文件,也就是所谓的分类器。
至此,分类器的训练工作已完成。剩下的,就是在程序中加载xml文件,并调用相应的函数接口来实现分类检测的作用了。
step1.首先是准备正负样本,正样本好说,打了标签,解析xml文件,然后做点小旋转就可以用了
负样本就复杂了,第一点要求是不能包含正样本,在我的应用场景中还需要尽可能多的提供场景的背景图,而不是网上所说的从网络上找一些不相干的图像,这些图像加进来促进作用也不大,因为我的场景中根本不会出现它们,但也不会出现负作用。第二是负样本数目尽可能的多,但这个还是量力而行吧,毕竟纯体力活,没多大的乐趣在里面。补充一句,样本的目录结构很简单,只要包含pos和neg两个子文件夹和opencv_haartraining.exe,
opencv_createsamples.exe,convert_cascade.exe等几个可执行程序,比如face-->face\train face\test
step2.生成正负样本描述文件,描述文件保存在face目录下与train test平级,命令如下:
打开cmd 分别cd 到正负样本目录
cd negdir
dir /b > negative.data
cd posdir
dir /b > positive.data
生成的描述文件当然还要替换才能够最终使用 对于positive.data只要在最后把jpg ->jpg 1 0 0 20 20,这里注意最好是在word下面替换好,再拷到txt下,速度快些,1 0 0 20 20的意思是这幅图片包含一个正样本目标,矩形区域为 0 0 20 20这里由于我们的正样本只有一个目标,而且已经大小归一化为20x20的图像,所以这里参数这么定义,而且opencv的坐标是从0开始的,我开始想过是不是要写成 0 0 19 19,本来看过网上一篇文章错写成1 1 20 20也没出错。正负样本的.data文件都要做的一件事是:打开.data文件,替换掉不是图片的行,比如positive.data negative.data.对于正样本,由于大小一致,为了避免过多的IO操作,可以生成vec文件,cd 到face目录 直接cd ..即可 然后输入命令:
opencv_createsamples.exe -info "pos/positive.data" -vec pos.vec -num 7097 -w 20 -h 20
其中-num指定你的正样本数目 -w 图像宽度,-h图像高度 生成描述文件
step3:经过上一步,准备工作已经做好,可以开始运行训练了,输入命令:
opencv_haartraining.exe -data haarcascade7097 -vec pos7097.vec -bg neg/negative.data -nstages 20 -nsplits 2 -minhitrate 0.999 -maxfalsealarm 0.5 -npos 7097 -nneg 7097 -w 20 -h 20 -mem 1024 -mode ALL
解释下各个参数的含义 -data 指定生成的文件目录, -vec vec文件名, -bg 负样本描述文件路径, -nstage 20 指定训练层数,推荐15~20,层数越高,耗时越长。-nsplits 分裂子节点数目,选取默认值 2 -minhitrate 最小命中率,即训练目标准确度。-maxfalsealarm最大虚警(误检率),每一层训练到这个值小于0.5时训练结束,进入下一层训练,-npos 正样本数目,-nneg 负样本数目 这个值可以设置大于真正的负样本图像数目,程序可以自动从负样本图像中切割出和正样本大小一致的 -nneg张图 这个参数一半设置为正样本数目的1~3倍, -w -h意思很明确, -mem 程序可使用的内存,这个设置为256即可,实际运行时根本就不怎么耗内存。 -mode ALL指定haar特征的类型数目
step3:然后就是等待了 ,我用上面的代码,负样本数目为2830,训练了一周,当然如果实在等不住了,中间结果也可以生成xml文件,命令如下:
/*转换为xml*/
convert_cascade.exe --size="20x20" ..\cascade ..\cascade.xml
ps:还有一个小建议:大家最好自己编译opencv,这样就可以vs--->project-->properties-->c++-->language-->OpenMp support 开启openmp选项,编译出来的exe就是多核并行的,提升速度很重要,我上面说的一周就是openmp加速在8核,3.2Ghz的服务器上跑的。
用别人的总有一天要还,想要最快,不会出错,最好自己写 haar+ adaboost ,这样选取负样本(最耗时的部分)的程序也可以并行加速了。waiting for me
最后添加几幅运行时图片:
这个是我跑到19层的结果,其中BACKGROUNG PROCESSING TIME 是负样本切割时间 很长很长
N 为训练层数 %SMP 样本占总样本个数 ST.THR 阈值,HR 击中率, FA 虚警 EXP.ERR 经验错误率
这个是指定的haarcasade7079 文件中生成的每一层文件的文件夹
文件和文件中的内容,然后使用
convert_cascade.exe --size="20x20" ..\cascade ..\cascade.xml就可以生成xml文件
祝大家玩的开心 有问题可以发信到gjtjx@163.com,只回复本文所包含的问题,
其他问题可以参看Opencv自带的doc 中haar训练的问题FAQ,还是参看英文原版的东西
节约时间.
关于正样本图片
createsamples -info positive_description.txt -vec samples.vec -w 20 -h 20
positive_image_name num_of_objects x y width height x y width height …
关于负样本图片
关于haartraining.exe的使用
haartraining -data haarcascade -vec samples.vec -bg negatives.dat -nstages 20 -minhitrate 0.999 -maxfalsealarm 0.5 -npos 1000 -nneg 2000 -w 20 -h 20 -nonsym -mem 1024
-data haarcascade
生成的xml文件目录为haarcascade
vec文件为samples.vec
负样本描述文件为negatives.dat
分类器的级联层数
-w -h参数与生成vec文件时设置的数值相同
= 0.0。
如果检测目标不是x或者y轴对称的,使用-nonsym选项。系统默认使用-sym选项
— 如果正负样本数目不相等,不要使用此选项
— 使用哪种adaboost算法:Real AB,Gentle AB等
树节点数的最小值
训练过程中,节点可使用的正样本数目。正样本根据节点被分类,通常来说,minpos不小于npos / nsplits
分类器xml文件
get XML from them?
convert_cascade –size=”20×20″ haarcascade haarcascade.xml
performance -data haarcascade -w 20 -h 20 -info positive_description.txt -ni
performance -data haarcascade.xml -info positive_description.txt -ni
使用OpenCV和训练得到的分类器检测物体