OPENCV训练模型

1.介绍

​ 使用Cascade Classifier包括两个主要阶段:训练阶段和检测阶段。需要用到的OpenCV应用程序:opencv_createssamples, opencv_annotation, opencv_traincascade和opencv_visualisation。opencv_createssamples和opencv_traincascade自OpenCV 4.0以来被禁用,但由于3.4和4.x的模型格式相同,因此可以采用3.4版本的程序进行模型训练。

2.准备训练数据

​ 为了训练一个模型,我们需要一组正样本(包含你想检测的实际对象)和一组负样本(包含你不想检测的所有东西)。负样本集必须手动准备,而正样本集则使用opencv_createssamples创建。

2.1.样本要求

  • 样本图片最好使用灰度图,且最好根据实际情况做一定的预处理;
  • 样本数量越多越好,尽量高于1000;
  • 样本间差异性越大越好;
  • 正负样本比例为1:3最佳;
  • 样本尺寸为20x20最佳;

2.2.获取训练程序

WINDOWS:
	下载地址https://opencv.org/releases/,目前4.x.x版本中没有训练程序,此处采用3.4.16版本,下载后安装就可以找到对应的exe文件;
LINUX:
	下载地址https://opencv.org/releases/,目前4.x.x版本中没有训练程序,此处采用3.4.16版本,编译后生成的目录为“build/bin”

2.3.准备目录和程序

  • negdata:放负样本的目录
  • posdata:放正样本的目录
  • opencv_annotation:用于在任何给定图像中可视化地选择对象实例感兴趣的对象,并创建info描述文件
  • opencv_createsamples:生成样本描述文件的可执行程序
  • opencv_traincascade:样本训练的可执行程序
  • opencv_visualisation:可视化训练后的级联,可以看到选择了哪些特征,以及它的阶段有多复杂

3.采集样本数据

3.1.正样本

​ 正样本是由opencv_createssamples应用程序创建的。应用程序支持两种生成正样本数据集的方法:

  • 方法1:从一个正样本图像中生成一堆正的样本图像
  • 方法2:自己提供所有的正样本图像,并且使用工具将它们剪切出来,调整它们的大小并将它们放入openv所需的二进制格式中

3.1.1.正样本生成方法1

​ 方法1对于固定对象非常有效,但对于不那么严格的对象,它往往很快就会失败,在这种情况下,建议使用方法2。OPENCV甚至指出,100个真实图像可以产生比1000个人工生成的更好的模型。如果依然决定采用方法1,请记住以下几点:

  • 请注意,在将其提供给应用程序前,您需要不止一个正样本,因为它只适用于透视图转换(perspective transformation)。
  • 如果您想要一个健壮的模型,那么请选取涵盖对象类中可能出现的各种类型的样本。例如,训练脸模型,应该考虑不同的种族、年龄、情绪,也许还有胡子的风格,这也适用于使用第二种方法。

​ 方法1采用单个对象图像,并随机旋转对象、改变图像强度以及将图像放置在任意背景上,从给定对象图像中创建大量正样本。随机性的数量和范围可以通过opencv_createssamples应用程序的命令行参数来控制。

​ opencv_createsamples的参数说明:

	-vec	用于训练的正样本的输出文件名
	-img	源对象图像
	-bg 	背景描述文件,包含一个图像列表,这些图像用作对象随机扭曲版本的背景
	-num 	生成的正样本数量
    -bgcolor	背景色(目前采用灰度图像),背景色为透明色。由于可能存在压缩伪影,因此可以通过-bgthresh指定颜色容错量。bgcolor-bgthresh和bgcolor+bgthresh范围内的所有像素都被解释为透明的。
    -bgthresh < background_color_threshold >
    -inv		如果指定,颜色将被反转
	-randinv	如果指定,颜色将随机反转
    -maxidev	前景样本中像素的最大强度偏差
    -maxxangle	朝向x轴的最大旋转角度,必须以弧度为单位
    -maxyangle	朝向y轴的最大旋转角度,必须以弧度为单位
    -maxzangle	朝向z轴的最大旋转角度,必须以弧度为单位
    -show		调试选项。如果指定,将显示每个样品。按Esc将继续示例创建过程,但不会显示每个示例
    -w			输出样本的宽度(像素)
    -h			输出样本的高度(像素)

​ 当以方法1运行opencv_createsamples时,使用以下过程来创建示例对象实例:

  • 给定的源图像围绕所有三个轴随机旋转。所选角度受-maxxangle, -maxyangle和-maxzangle的限制
  • 像素的亮度从[bg_color-bg_color_threshold;Bg_color +bg_color_threshold]范围被解释为透明。白噪声被添加到前景的强度中
  • 如果指定了-inv,则前景像素强度反转。如果指定-randinv key,则算法随机选择是否对该样本进行反转
  • 最后,将获得的图像从背景描述文件放置到任意背景上,将其大小调整为-w和-h指定的所需大小,并存储到由-vec指定的vec文件中

3.1.2.正样本生成方法2

​ 正样本也可以从先前标记的图像集合中获得,这是构建robust对象模型时所需的方法。该集合由一个类似于背景描述文件的文本文件描述。这个文件的每一行都对应一个图像。该行的第一个元素是文件名,然后是对象注释的数量,然后是描述对象边界矩形(x, y,宽度,高度)的坐标的数字。

​ 进入posdata目录,然后创建 pos.txt,目录格式如下:

/posdata
	00001.jpg 
	00002.jpg 
	00003.jpg 
	pos.txt

​ pos.txt的内容如下:

00001.jpg 3 548 605 95 100 771 641 125 94 1199 634 182 269
00002.jpg 5 333 464 115 148 844 610 205 259 1139 460 98 138 1315 461 93 101 943 503 57 78
00003.jpg 5 5 491 103 156 472 517 80 114 845 449 151 177 877 631 148 203 1292 482 68 91

​ 图像00001.jpg包含了3个对象,分别是{548,605,95,100},{771,641,125,94},{1199,634,182,269}

​ 为了从这样的集合中创建正样本,应该指定-info参数而不是-img。注意,在方法2中,-bg、-bgcolor、-bgthreshold、-inv、-randinv、-maxxangle、-maxyangle、-maxzangle等参数将被忽略,不再使用。方法2创建示例的方案如下:

  • 从原始图像中剪切提供的边界框,从给定图像中获取对象实例
  • 将它们调整为目标样本大小(由-w和-h定义),并存储在由-vec参数定义的输出vec文件中
  • 方法2唯一有影响的参数是-w, -h, -show和-num

生成VEC指令:

opencv_createsamples -info ${FILEINFO_POS} -vec ${FILEVEC_POS} -num ${NUM_POS} -bgcolor 0 -bgthresh 0 ${SIZ_POS}

3.1.3.opencv_annotation工具

​ 创建info描述文件的过程也可以通过使用opencv_annotation工具来完成。这是一个开源工具,用于在任何给定图像中可视化地选择对象实例感兴趣的区域。

​ 使用该工具非常简单。该工具接受几个必需的和一些可选的参数:

-?, -h, --help, --usage (value:true)
					显示帮助信息
-a, --annotations 	必选参数,指定生成info描述文件的路径
-i,--images			必选参数,包含样本的目录路径
-m,--maxWindowHeight	可选参数,如果输入图像的高度大于这里给定的分辨率,请使用resizeFactor调整图像的大小
-r,--resizeFactor		可选参数,当使用maxWindowHeight参数时,用于调整输入图像大小的因子(默认:一半大小)。

​ 示例:

./opencv_annotation -a=sample_people/posdata/pos.txt -i=sample_people/posdata/

​ opencv_annotation命令将打开一个窗口,其中包含第一个图像和用于注释的鼠标光标。鼠标左键用于选择对象的第一个角,然后继续绘制直到确定为止,并在第二次单击鼠标左键时停止。每次选择后,您有以下选择:
​ 按c键:确认标注,标注变为绿色,确认已保存
​ 按d键:从注释列表中删除最后一个注释(方便删除错误注释)
​ 按n键:继续下一个图像
​ 按ESC:退出注释软件
​ 最后,您将得到一个可用的注释文件,它可以传递给opencv_createssamples的-info参数。

3.2.负样本

​ 负样本取自任意图像,图像中应不包含想要检测的对象。这些负样本图像被记录在一个负样本描述文件中,描述文件的每行包含一个图像的路径(可以是绝对路径或相对路径)。请注意,负样本和样本图像也称为背景样本或背景图像。

​ 描述的图像可能有不同的大小,然而每个图像都应该等于或大于期望的训练窗口大小(模型尺寸,大多数情况下是对象的平均大小)。

​ 负样本也不能随意的找些图片来作为负样本。最好根据不同的项目选择不同的负样本。比如一个项目是做机场的人脸检测,那么就最好从现场拍摄一些图片数据回来,从中采集负样本。不同的项目,就采集不同的正样本和负样本。

​ 进入negdata目录,然后创建 neg.txt,目录格式如下:

/negdata
	00001.jpg
	00002.jpg
	00003.jpg
	00004.jpg
	neg.txt

​ neg.txt的内容如下:

00001.jpg
00002.jpg
00003.jpg
00004.jpg

4.模型训练

通用参数:

-data		训练好的分类器存储的位置,这个文件夹应该事先手动创建
-vec 		带有正样本的vec文件
-bg 		背景描述文件,包含负样本图像的文件
-numPos 	每个分类器阶段训练中使用的正样本数量。
-numNeg		每个分类器阶段训练中使用的负样本数量。
-numStages 	要训练的级联阶段的数量。
-precalcValBufSize 	预计算特征值的缓冲区大小(单位为Mb)。
-precalcIdxBufSize	预计算特征索引的缓冲区大小(单位:Mb)。
	注意:precalcValBufSize和precalcIdxBufSize分配的内存越多,训练过程就越快,但是不应超过可用的系统内存。
-baseFormatSave		仅在使用Haar特征时有效。如果指定了该参数,则级联将以旧格式保存。
-numThreads 训练期间使用的最大线程数。注意,实际使用的线程数可能更少,这取决于您的机器和编译选项。默认情况下,如果您使用TBB支持构建OpenCV,则选择最大可用线程,这是此优化所需要的。
-acceptanceRatioBreakValue	用于确定你的模型应该保持学习的精确程度以及何时停止。一个好的指导方针是训练不超过10e-5,以确保模型不会在你的训练数据上过度训练。缺省情况下,该值设置为-1,表示禁用该特性。

级联参数

-stageType		级别(stage)参数。目前只支持将BOOST分类器作为级联的类型;
-featureType	特征的类型:HAAR-类Haar特征;LBP-局部二进制模式(默认Harr);
如果遇到的教程提到旧的opencv_haartraining工具(已弃用),请忽略该教程并使用opencv_traincascade工具。openv_traincascade同时支持HAAR和LBP特征。与HAAR特征相比,LBP特征产生整数精度,产生浮点精度,因此LBP的训练和检测速度都比HAAR特征快几倍。对于LBP和HAAR的检测质量,主要取决于所使用的训练数据和所选择的训练参数。
-w 	训练样本的度(像素,默认24);
-h	训练样本的度(像素,默认24);
注意:训练样本的尺寸必须跟训练样本创建(使用 opencv_createsamples 程序创建)时的尺寸保持一致

Boosted分类器参数

-bt	
	Boosted分类器的类型(DAB-Discrete AdaBoost, RAB-Real AdaBoost, LB-LogitBoost,GAB-Gentle AdaBoost为默认);
-minHitRate	
	每个阶段的最小期望命中率(默认值为0.995)。总命中率可以估计为(minHitRate^ number_of_stages)
-maxFalseAlarmRate 
	每一级希望得到的最大误检率(默认值为0.5),总的误检率大约为 maxFalseAlarmRate^number_of_stages;
-weightTrimRate	
	是否应该使用微调及其权重。一个不错的选择是0.95。
-maxDepth 		
	弱树的最大深度。一个合适的选择是1,这是树桩的情况。
-maxWeakCount 
	每个级联阶段弱树的最大计数(默认值为100)。boosted分类器(阶段)将有许多弱树(<=maxWeakCount),以实现给定的-maxFalseAlarmRate。

Haar-like 特征参数

-mode 
	选择训练中使用的Haar特征集的类型。BASIC只使用直立特征,而ALL使用全套直立和45度旋转特征集。

​ opencv_traincascade应用程序完成其工作后,训练好的级联将保存在-data文件夹中的cascade.xml文件中。此文件夹中的其他文件是为培训中断而创建的,您可以在培训结束后删除。

训练指令:

opencv_traincascade -data ${PATH_OUT} -vec ${FILEVEC_POS} -bg ${FILEINFO_NEG}  -numPos ${NUM_POS} -numNeg ${NUM_NEG} -numStages 20 -feattureType HAAR ${SIZ_POS} -minHitRate 0.995 -maxFalseAlarmRate 0.5

5.可视化级联分类器opencv_visualisation

​ 可视化训练后的级联是很有用的,可以看到它选择了哪些特征,以及它的阶段有多复杂。为此,OpenCV提供了一个opencv_visualisation应用程序。这个应用程序有以下命令:

-?, -h, --help, --usage
	显示帮助信息
-d, --data
	(可选)如果提供了一个数据文件夹,必须事先手动创建,将存储阶段输出和特征的视频
-i, --image 
	(必选):指向对象模型的参考图像的路径。应该是一个维度为[-w,-h]的注释(annotation),同时传递给opencv_createssamples和opencv_traincascade应用程序。
-m, --model 
	(必选):训练模型的路径,它应该在openv_traincascade应用程序的-data参数提供的文件夹中。

​ 示例

./opencv_visualisation -m=output/sample_people/cascade.xml -d=output/sample_people/ -i=sample_people/posdata/object.jpg

​ 当前可视化工具的一些局限性

  • 只处理用opencv_traincascade工具训练的级联分类器模型,包含树桩作为决策树[默认设置]。
  • 所提供的图像需要是具有原始模型尺寸的示例窗口,并传递给–image参数。

6.问题解决

6.1.问题1

问题描述:Traincascade Error: Bad argument (Can not get new positive sample. The most possible reason is insufficient count of samples in given vec-file.

解决办法:主要是numPos的值设置的不对,把numPos简单设置成正样本数量,将numPos设置正样本数量*4/5即可。

6.2.问题2

问题描述:(-215:Assertion failed) !ssize.empty() in function ‘resize’

解决办法:描述文件中的样本点数据错误导致;

7.后语

​ 基于人头(正样本4100,负样本23240)、汽车(正样本516,负样本1044)、行人((正样本1126,负样本1000))和实际环境(正样本79,负样本19)训练,感觉最终的效果都不是很好。有知道原因,或者有想法的可以一起交流。

猜你喜欢

转载自blog.csdn.net/weixin_35804181/article/details/130870753