上一个教程: 级联分类器
下一个教程: 支持向量机简介
简介
使用升压级联的弱分类器工作包括两个主要阶段:训练和检测阶段。使用基于HAAR或LBP模型的检测阶段,在对象检测教程中有所描述。本文档概述了训练你自己的弱分类器的提升级联所需的功能。目前的指南将走过所有不同的阶段:收集训练数据、准备训练数据和执行实际的模型训练。
为了支持本教程,将使用几个官方的OpenCV应用程序:opencv_createsamples、opencv_annotation、opencv_traincascade和opencv_visualisation。
注意事项
从OpenCV4.0开始,Createsamples和traincascade被禁用。考虑使用这些应用程序来训练3.4分支的级联分类器。模型格式在3.4和4.x之间是相同的。
重要说明
- 如果你遇到任何教程提到旧的opencv_haartraining工具(该工具已经废弃,仍然使用OpenCV1.x的接口),那么请忽略该教程,坚持使用opencv_traincascade工具。这个工具是一个较新的版本,按照OpenCV 2.x和OpenCV 3.x的API用C++编写。opencv_traincascade支持类似HAAR的小波特征[266]和LBP(局部二进制模式)[149]特征。LBP特征产生整数精度,而HAAR特征产生浮点精度,因此使用LBP的训练和检测都比使用HAAR特征快几倍。关于LBP和HAAR的检测质量,主要取决于使用的训练数据和选择的训练参数。我们有可能训练出一个基于LBP的分类器,在一定的训练时间内提供与基于HAAR的分类器几乎相同的质量。
- 来自OpenCV 2.x和OpenCV 3.x的较新的级联分类器检测接口(cv::CascadeClassifier)支持使用新旧两种模型格式。如果因为某些原因你坚持使用旧的接口,opencv_traincascade甚至可以保存(导出)一个训练好的级联的格式。至少训练模型可以在最稳定的界面上完成。
- opencv_traincascade应用程序可以使用TBB进行多线程处理。要在多核模式下使用它,OpenCV的构建必须启用TBB支持。
训练数据的准备
为了训练弱分类器的升压级联,我们需要一组阳性样本(包含你想检测的实际物体)和一组阴性图像(包含你不想检测的一切)。阴性样本集必须手工准备,而阳性样本集则使用opencv_createsamples应用程序创建。
阴性样本
阴性样本取自任意图像,不包含你想要检测的对象。这些生成样本的阴性图像应该被列在一个特殊的阴性图像文件中,每行包含一个图像路径(可以是绝对的或相对的)。注意,负片样本和样本图像也被称为背景样本或背景图像,在本文件中可以互换使用。
所描述的图像可以有不同的尺寸。然而,每张图像应该等于或大于所需的训练窗口尺寸(对应于模型尺寸,大多数时候是你的物体的平均尺寸),因为这些图像被用来将给定的负片图像子样化为具有该训练窗口尺寸的若干图像样本。
这样一个负片描述文件的例子:
目录结构:
/img
img1.jpg
img2.jpg
bg.txt
文件bg.txt:
img/img1.jpg
img/img2.jpg
你的阴性窗口样本集将被用来告诉机器学习步骤,在这种情况下,在试图寻找你感兴趣的对象时,不要寻找什么。
阳性样本
阳性样本是由opencv_createsamples应用程序创建的。它们被提升过程用来定义模型在试图找到你感兴趣的对象时应该实际寻找的东西。该应用程序支持两种生成正样本数据集的方式。
- 你可以从一个单一的阳性物体图像中生成一堆阳性物体。
- 你可以自己提供所有的阳性物体,只用这个工具把它们剪下来,调整它们的大小,并把它们放到opencv需要的二进制格式中。
虽然第一种方法对于固定的物体,如非常坚硬的标志,效果很好,但对于不太坚硬的物体,它往往很快就会失败。在这种情况下,我们确实建议使用第二种方法。网络上的许多教程甚至指出,通过使用opencv_createsamples应用程序,100张真实的物体图像可以产生比1000张人工生成的正片更好的模型。然而,如果你确实决定采取第一种方法,请记住一些事情:
- 请注意,在你把它交给上述应用程序之前,你需要多于一个阳性样本,因为它只应用透视变换。
- 如果你想要一个健壮的模型,那么你的样本要涵盖你的对象类中可能出现的广泛种类。例如,在面孔的情况下,你应该考虑不同的种族和年龄组、情绪,也许还有胡须风格。这也适用于使用第二种方法。
第一种方法需要一个单一的对象图像,例如一个公司的标志,并通过随机旋转对象、改变图像强度以及将图像放在任意的背景上,从给定的对象图像中创建一个大的正样本集。随机性的数量和范围可以通过opencv_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 <背景色_阈值>。
-inv
: 如果指定,颜色将被倒置。-randinv
: 如果指定,颜色将被随机倒置。-maxidev <max_intensity_deviation>
: 前景样本中像素的最大强度偏差。-maxxangle <max_x_rotation_angle>
: 面向X轴的最大旋转角度,必须以弧度为单位。-maxyangle <max_y_rotation_angle>
: 对Y轴的最大旋转角度,必须用弧度表示。-maxzangle <max_z_rotation_angle>
: 对Z轴的最大旋转角度,必须以弧度为单位。-show
: 有用的调试选项。如果指定,每个样本都会被显示出来。按Esc键将继续创建样本的过程而不显示每个样本。-w <sample_width>
: 输出样本的宽度(像素)。-h <sample_height>
: 输出样本的高度(单位:像素)。
当以这种方式运行opencv_createsamples时,以下程序被用来创建一个样本对象实例: 给定的源图像围绕所有三个轴随机旋转。选择的角度由-maxxangle
、-maxyangle
和-maxzangle
限制。然后,具有[bg_color-bg_color_threshold; bg_color+bg_color_threshold]范围内强度的像素被解释为透明。白噪声被添加到前景的强度中。如果指定了-inv
键,那么前景像素的强度将被反转。如果指定了-randinv
键,那么算法会随机选择是否要对这个样本进行反转。最后,获得的图像被放置在一个来自背景描述文件的任意背景上,调整到由-w
和-h
指定的所需大小,并存储到由-vec
命令行选项指定的vec-文件中。
正面样本也可以从先前标记过的图像集合中获得,这是在建立健壮的物体模型时需要的方式。这个集合由一个类似于背景描述文件的文本文件来描述。这个文件的每一行都对应于一个图像。这一行的第一个元素是文件名,接着是物体注释的数量,然后是描述物体边界矩形坐标的数字(x、y、宽度、高度)。
一个描述文件的例子:
目录结构:
/img
img1.jpg
img2.jpg
info.dat
文件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)。图片img2.jpg包含两个对象实例。
为了从这样的集合中创建正面样本,应该指定-info
参数而不是-img
:
-info <collection_file_name>
: 标记的图像集合的描述文件。
注意,在这种情况下,像-bg, -bgcolor, -bgthreshold, -inv, -randinv, -maxxangle, -maxyangle, -maxzangle
这样的参数被简单地忽略,不再使用。这种情况下的样本创建方案如下。对象实例是从给定的图像中提取的,通过从原始图像中切出所提供的边界框。然后,它们被调整为目标样本大小(由-w
和-h
定义),并存储在由-vec
参数定义的输出vec-文件中。没有变形,所以唯一影响参数是-w、-h、-show
和-num
。
手动创建-info
文件的过程也可以通过使用opencv_annotation工具完成。这是一个开源的工具,用于在任何给定的图像中直观地选择对象实例的感兴趣区域。下面的小节将更详细地讨论如何使用这个应用程序。
额外说明
- opencv_createsamples工具可以用来检查存储在任何给定的正样本文件中的样本。为了做到这一点,只需要指定
-vec、-w
和-h
参数。 - vec文件的例子可以在这里找到
opencv/data/vec_files/trainingfaces_24-24.vec
。它可以用来训练人脸检测器,窗口大小如下:-w 24 -h 24
。
使用OpenCV的集成注解工具
从OpenCV 3.x开始,社区一直在提供和维护一个开源的注释工具,用于生成-info文件。如果OpenCV的应用程序已经建立,可以通过命令opencv_annotation访问该工具。
使用该工具是非常简单的。该工具接受几个必要的和一些可选的参数:
--annotations
(必填):注释txt文件的路径,你想把你的注释储存在那里,然后传递给-info参数[例子-/data/annotations.txt] 。--images
(必填) : 包含你的对象的图片的文件夹的路径 [example - /data/testimages/]--maxWindowHeight
(可选):如果输入图像的高度大于这里给定的分辨率,则使用--resizeFactor
调整图像的大小,以方便注释。--resizeFactor
(可选):当使用--maxWindowHeight
参数时,用于调整输入图像的大小的系数。
注意,这些可选参数只能一起使用。下面是一个可以使用的命令的例子
opencv_annotation --annotations=/path/to/annotations/file.txt --images=/path/to/image/folder/
这个命令将启动一个包含第一张图片和你的鼠标光标的窗口,该窗口将被用于注释。关于如何使用注释工具的视频可以在这里找到。基本上,有几个按键可以触发一个动作。鼠标左键用来选择你的对象的第一个角,然后继续画,直到你画好为止,当第二次鼠标左键点击注册时就会停止。每次选择后,你有以下选择:
- 按
c
:确认注解,将注解变成绿色并确认其被存储 - 按
d
:从注解列表中删除最后一个注解(便于删除错误的注解)。 - 按
n
:继续到下一张图片 - 按
ESC
键:这将退出注释软件
最后你会得到一个可用的注释文件,可以传递给opencv_createsamples的-info
参数。
级联训练
下一步是基于事先准备好的正负数据集,对弱分类器的提升级联进行实际训练。
opencv_traincascade应用程序的命令行参数按目的分组:
- 常用参数:
-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>
: 每个分类器阶段训练中使用的负样本数量。-numStages <number_of_stages>
: 要训练的级联阶段的数量。-precalcValBufSize <precalculated_vals_buffer_size_in_Mb>
: 预计算特征值的缓冲区大小(Mb)。你分配的内存越多,训练过程就越快,但是请记住,-precalcValBufSize
和-precalcIdxBufSize
加起来不应该超过你的可用系统内存。-precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb>
: 用于预计算特征指数的缓冲区大小(Mb)。你分配的内存越多,训练过程就越快,但是请记住,-precalcValBufSize
和-precalcIdxBufSize
加起来不应该超过你的可用系统内存。-baseFormatSave
:这个参数对于类似Haar的特征来说是实际的。如果指定了它,级联将以旧的格式保存。这只是为了向后兼容的原因,并允许坚持使用旧的废弃接口的用户至少使用较新的接口来训练模型。-numThreads <max_number_of_threads>
: 训练时使用的最大线程数。注意,实际使用的线程数可能更少,这取决于你的机器和编译选项。默认情况下,如果你在构建OpenCV时支持TBB,就会选择最大的可用线程,这对于这个优化来说是需要的。-acceptanceRatioBreakValue <break_value>
: 这个参数用来决定你的模型应该保持多精确的学习以及何时停止。一个好的指导原则是,训练不要超过10e-5,以确保模型不会在训练数据上过度训练。默认情况下,这个值被设置为-1,以禁用这个功能。
- 级联参数:
-stageType <BOOST(default)>
: 阶段的类型。目前只支持boosted分类器作为一个阶段的类型。-featureType<{HAAR(default), LBP}>
: 特征的类型: HAAR–类Haar特征,LBP–局部二进制模式。-w <sampleWidth>
: 训练样本的宽度(单位:像素)。必须与创建训练样本时使用的值完全相同(opencv_createsamples工具)。- -h : 训练样本的高度(像素)。必须与创建训练样本时使用的值完全相同(opencv_createsamples utility)。
- 提升分类器的参数:
-bt <{DAB, RAB, LB, GAB(default)}>
: 提升分类器的类型: DAB - Discrete AdaBoost, RAB - Real AdaBoost, LB - LogitBoost, GAB - Gentle AdaBoost。-minHitRate <min_hit_rate>
: 分类器每个阶段的最小期望命中率。总体命中率可以估计为(min_hit_rate ^ number_of_stages),[267] §4.1。-maxFalseAlarmRate <max_false_alarm_rate>
: 分类器每个阶段的最大期望误报率。总体误报率可以估计为(max_false_alarm_rate ^ number_of_stages), [267] §4.1。-weightTrimRate <weight_trim_rate>
: 指定是否应该使用修剪和它的权重。一个不错的选择是0.95。-maxDepth <max_depth_of_weak_tree>
: 弱树的最大深度。一个不错的选择是1,这是树桩的情况。-maxWeakCount <max_weak_tree_count>
: 每个级联阶段的弱树的最大数量。提升的分类器(阶段)将有这么多的弱树(<=maxWeakCount),以达到给定的-maxFalseAlarmRate
。
- 类Haar特征参数:
-mode <BASIC (default) | CORE | ALL>
: 选择训练中使用的Haar特征集的类型。BASIC只使用直立特征,而ALL使用全套直立和45度旋转的特征集。更多细节见[152]。
- 局部二进制模式参数: 局部二进制模式没有参数。
在opencv_traincascade应用程序完成其工作后,训练好的级联将被保存在-data文件夹中的cascade.xml文件中。这个文件夹中的其他文件是为中断训练的情况下创建的,所以你可以在训练完成后删除它们。
训练结束了,你可以测试你的级联分类器了!
级联分类器的可视化
时不时地将训练后的级联进行可视化,看看它选择了哪些特征以及它的阶段有多复杂,这是很有用的。为此,OpenCV提供了一个opencv_visualisation应用程序。这个应用程序有以下命令:
--image
(必选) : 为你的对象模型提供一个参考图像的路径。这应该是一个尺寸为[-w,-h]的注释,并传递给opencv_createsamples和opencv_traincascade应用程序。--model
l(必选) : 训练好的模型的路径,它应该在opencv_traincascade应用程序的-data参数所提供的文件夹中。--data
(可选):如果提供了一个数据文件夹,必须事先手动创建,阶段输出和特征视频将被存储。
下面是一个命令的例子
opencv_visualisation --image=/data/object.png --model=/data/model.xml --data=/data/result/
当前可视化工具的一些局限性
- 只处理用opencv_traincascade工具训练的级联分类器模型,包含决策树的树桩【默认设置】。
- 提供的图像需要是一个具有原始模型尺寸的样本窗口,传递给
--image
参数。
HAAR/LBP脸部模型在安吉丽娜-朱莉的给定窗口上运行的例子,其预处理与级联分类器文件相同->24x24像素的图像,灰度转换和直方图均衡化:
在每个阶段,每个特征都被可视化,并制作成视频:
每个阶段都被存储为图像,以便将来验证特征:
这项工作是由StevenPuttemans为OpenCV 3 Blueprints创建的,但Packt Publishing同意将其整合到OpenCV中。