Skip to content

级联分类器训练

使用弱分类器的提升级联包括两个主要阶段:训练阶段和检测阶段。使用基于 HAAR 或 LBP 模型的检测阶段在 目标检测教程 中有说明。本文档概述了训练你自己的弱分类器提升级联所需的功能。本指南将走完所有不同的阶段:收集训练数据、准备训练数据以及执行实际的模型训练。

为支持本教程,将使用几个官方的 OpenCV 应用程序:opencv_createsamples、opencv_annotation、opencv_traincascade 和 opencv_visualisation。

注意: Createsamples 和 traincascade 自 OpenCV 4.0 起已禁用。考虑在 3.4 分支中使用这些应用程序来训练级联分类器。3.4 和 4.x 之间的模型格式是相同的。

  • 如果你遇到任何提及旧的 opencv_haartraining 工具它已被弃用,且仍在使用 OpenCV1.x 接口的教程,请忽略该教程并坚持使用 opencv_traincascade 工具。此工具是一个较新的版本,用 C++ 编写,符合 OpenCV 2.x 和 OpenCV 3.x API。opencv_traincascade 支持 HAAR 类小波特征 和 LBP(Local Binary Patterns) 特征。与产生浮点精度的 HAAR 特征相比,LBP 特征产生整数精度,因此使用 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

你的负窗口样本集将用于告诉机器学习步骤(在本例中为 boosting),在试图找到你感兴趣的目标时不要寻找什么。

正样本由 opencv_createsamples 应用程序创建。提升过程使用它们来定义当试图找到你感兴趣的目标时模型实际应当寻找什么。该应用程序支持两种生成正样本数据集的方式。

  1. 你可以从单个正样本目标图像生成大量正样本。
  2. 你可以自己提供所有正样本,并仅使用该工具将它们剪切出来、调整大小并将它们放入 opencv 所需的二进制格式。

虽然第一种方法对于固定目标(如非常刚性的徽标)效果不错,但对于不太刚性的目标很快就会失败。在这种情况下,我们建议使用第二种方法。网上的许多教程甚至指出,100 张真实目标图像,通过使用 opencv_createsamples 应用程序,可以比 1000 张人工生成的正样本产生更好的模型。但是,如果你决定采用第一种方法,请记住以下几点:

  • 请注意,在将其交给上述应用程序之前,你需要不止一个正样本,因为它只应用透视变换。
  • 如果你想要一个鲁棒的模型,请采样覆盖目标类别内可能出现的各种变化。例如,在人脸的情况下,你应当考虑不同的种族和年龄组、表情以及可能的胡须样式。这在使用第二种方法时同样适用。

第一种方法以一张目标图像(例如公司徽标)为例,通过随机旋转目标、改变图像强度以及将图像放置在任意背景上,从给定目标图像创建大量正样本。随机性的数量和范围可以通过 opencv_createsamples 应用程序的命令行参数来控制。

命令行参数:

  • -vec:包含用于训练的正样本的输出文件名。

  • -img:源目标图像(例如公司徽标)。

  • -bg:背景描述文件;包含用作目标随机变形版本背景的图像列表。

  • -num:要生成的正样本数量。

  • -bgcolor:背景颜色(目前假定是灰度图像);背景颜色表示透明颜色。由于可能存在压缩伪影,颜色容差量可由 -bgthresh 指定。bgcolor-bgthresh 和 bgcolor+bgthresh 范围内的所有像素都被解释为透明的。

  • -bgthresh

  • -inv:如果指定,颜色将被反转。

  • -randinv:如果指定,颜色将被随机反转。

  • -maxidev:前景样本中像素的最大强度偏差。

  • -maxxangle:绕 x 轴的最大旋转角度,必须以弧度给出。

  • -maxyangle:绕 y 轴的最大旋转角度,必须以弧度给出。

  • -maxzangle:绕 z 轴的最大旋转角度,必须以弧度给出。

  • -show:有用的调试选项。如果指定,将显示每个样本。按 Esc 将继续创建样本的过程,而不显示每个样本。

  • -w:输出样本的宽度(以像素为单位)。

  • -h:输出样本的高度(以像素为单位)。

以这种方式运行 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:标注好的图像集合的描述文件。

注意,在这种情况下,像 -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 3.x 起,社区一直在提供和维护一个开源标注工具,用于生成 -info 文件。如果 OpenCV 应用程序已构建,则可以通过 opencv_annotation 命令访问该工具。

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

  • --annotations (必需):注释 txt 文件的路径,你希望在其中存储注释,然后将其传递给 -info 参数 [示例 - /data/annotations.txt]
  • --images (必需):包含带目标的图像的文件夹路径 [示例 - /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:训练好的分类器应当存储的位置。此文件夹应当事先手动创建。
    • -vec:带有正样本的 vec 文件(由 opencv_createsamples 实用程序创建)。
    • -bg:背景描述文件。这是包含负样本图像的文件。
    • -numPos:每个分类器阶段训练中使用的正样本数量。
    • -numNeg:每个分类器阶段训练中使用的负样本数量。
    • -numStages:要训练的级联阶段数。
    • -precalcValBufSize:预计算特征值的缓冲区大小(以 Mb 为单位)。分配的内存越多,训练过程越快,但请记住,-precalcValBufSize 和 -precalcIdxBufSize 加起来不应超过你可用的系统内存。
    • -precalcIdxBufSize:预计算特征索引的缓冲区大小(以 Mb 为单位)。分配的内存越多,训练过程越快,但请记住,-precalcValBufSize 和 -precalcIdxBufSize 加起来不应超过你可用的系统内存。
    • -baseFormatSave:此参数在 Haar 类特征的情况下有效。如果指定,级联将以旧格式保存。这仅出于向后兼容的原因而提供,并允许坚持使用旧的已弃用接口的用户至少使用较新的接口来训练模型。
    • -numThreads:训练期间使用的最大线程数。请注意,实际使用的线程数可能较低,具体取决于你的机器和编译选项。默认情况下,如果你在启用 TBB 支持的情况下构建了 OpenCV(此优化需要 TBB 支持),则选择最大可用线程数。
    • -acceptanceRatioBreakValue:此参数用于确定你的模型应当保持学习的精确程度以及何时停止。一个好的准则是训练不超过 10e-5,以确保模型不会在你的训练数据上过训练。默认情况下,此值设置为 -1 以禁用此功能。
  • 级联参数:

    • -stageType:阶段的类型。目前仅支持提升分类器作为阶段类型。
    • -featureType:特征的类型:HAAR - Haar 类特征,LBP - 局部二值模式。
    • -w:训练样本的宽度(以像素为单位)。必须与创建训练样本(opencv_createsamples 实用程序)期间使用的值完全相同。
    • -h:训练样本的高度(以像素为单位)。必须与创建训练样本(opencv_createsamples 实用程序)期间使用的值完全相同。
  • 提升分类器参数:

    • -bt:提升分类器的类型:DAB - Discrete AdaBoost,RAB - Real AdaBoost,LB - LogitBoost,GAB - Gentle AdaBoost。
    • -minHitRate:分类器每个阶段所需的最小命中率。总命中率可以估计为 (min_hit_rate ^ number_of_stages), §4.1。
    • -maxFalseAlarmRate:分类器每个阶段所需的最大误报率。总误报率可以估计为 (max_false_alarm_rate ^ number_of_stages), §4.1。
    • -weightTrimRate:指定是否应使用修剪及其权重。一个不错的选择是 0.95。
    • -maxDepth:弱树的最大深度。一个不错的选择是 1,即树桩的情况。
    • -maxWeakCount:每个级联阶段的最大弱树数量。提升分类器(阶段)将具有达到给定 -maxFalseAlarmRate 所需的那么多弱树(≤maxWeakCount)。
  • Haar 类特征参数:

    • -mode:选择训练中使用的 Haar 特征集的类型。可选值:BASIC(默认)、CORE、ALL。BASIC 仅使用直立特征,而 ALL 使用完整的直立和 45 度旋转特征集。
  • 局部二值模式参数:局部二值模式没有参数。

opencv_traincascade 应用程序完成其工作后,训练好的级联将保存在 -data 文件夹中的 cascade.xml 文件中。此文件夹中的其他文件是为训练中断的情况创建的,因此你可以在训练完成后删除它们。

训练完成,你可以测试你的级联分类器了!

有时可视化训练好的级联很有用,以查看它选择了哪些特征以及其阶段的复杂程度。为此,OpenCV 提供了一个 opencv_visualisation 应用程序。此应用程序具有以下命令:

  • --image (必需):目标模型的参考图像路径。这应当是一个尺寸为 [-w,-h] 的标注,与传递给 opencv_createsamples 和 opencv_traincascade 应用程序的相同。
  • --model (必需):训练好的模型路径,它应当位于传递给 opencv_traincascade 应用程序的 -data 参数的文件夹中。
  • --data (可选):如果提供了数据文件夹(必须事先手动创建),则将存储阶段输出和特征视频。

下面可以看到一个示例命令

opencv_visualisation --image=/data/object.png --model=/data/model.xml --data=/data/result/

visualisation_video.png visualisation_single_stage.png

当前可视化工具的一些限制

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

在给定 Angelina Jolie 窗口上运行 HAAR/LBP 人脸模型的示例,该窗口与级联分类器文件具有相同的预处理 →24x24 像素图像、灰度转换和直方图均衡化:

为每个阶段每个特征制作了一个可视化视频:

每个阶段存储为图像,用于将来对特征进行验证:

此作品由 StevenPuttemans 为 OpenCV 3 Blueprints 创建,Packt Publishing 同意将其集成到 OpenCV 中。