一、介绍
目前常用的实用性目标检测与跟踪的方式方法有以下两种
- 帧差法:识别原理就是基于前后两帧图像之间的差异进行对比,获取图像画面中正在运动的物体从而达到目标检测,缺点是画面中所有运动中物体都能识别,例如需要是被的是车辆运动,但是画面中风吹动树叶飘动也会被计算在甄别范围内,这就导致甄别物出现错误
- CascadeClassifier级联分类器:那么如果只是识别车辆,那就需要把车辆需要相关信息全部统计出来(颜色、形状、大小等信息),存储在一个文件中。这个文件就叫级联分类器。级联分类器也是机器视觉和机器学习中非常重要的一个环节;
级联增强分类器包含两个主要阶段:训练阶段和检测阶段。检测阶段使用HAAR或在LBP基础模型。通过以下几个部分进行讲解,分别是:收集训练数据、准备训练数据和执行实际模型训练。主要用到opencv 官方的几个应用程序:opencv_createsamples、opencv_annotation、opencv_traincascade和opencv_visualization。
自 OpenCV 4.0 起,Createsamples 和 traincascade 被禁用。考虑使用这些应用程序从 3.4 分支进行级联分类器的训练。3.4 和 4.x 之间的模型格式相同。需要编译2.x或3.4之间的opencv版本才会有上面几个应用程序。
opencv_traincascade 支持类似 HAAR 的小波特征[269]和 LBP(局部二进制模式)[152]特征。LBP 特征产生整数精度,与 HAAR 特征相比,产生浮点精度,因此使用 LBP 进行训练和检测比使用 HAAR 特征快几倍。对于LBP和HAAR检测质量,主要取决于所使用的训练数据和选择的训练参数。训练基于 LBP 的分类器是可能的,该分类器将在训练时间的一定百分比内提供与基于 HAAR 的分类器几乎相同的质量。
HAAR与LBP的区别
- HAAR特征是浮点数计算
- LBP特征是整数计算
- LBP训练需要的样本数量要比HAAR大
- 同样的样本空间,HAAR训练出来的数据检测结果 要比LBP准确
- 扩大LBP的样本数据,训练结果可以跟HAAR一样
- LBP的速度一般可以比HAAR快几倍
- HAAR比LBP要准确
二、训练流程
- 收集样本数据-包括正负样本
- 样本集合及描述文件
- 调用opencv_createsamples程序实现样本数据采集
- 调用opencv_traincascade样本训练程序进行训练
- 生成级联分类器文件;
1、收集样本数据
为了训练,我们需要一组样本。有两种类型的样本:负样本和正样本。负样本对应于非对象图像。正样本对应于检测到物体的图像。负样本集必须手动准备,而正样本集是使用opencv_createsamples
实用程序创建的。
- 正样本。包含待检测目标的图片。要统一尺寸,即长宽比例要相同(1:1)(1:2)。例如车辆识别,提供的各种需要识别的车的图片。正样本要求尽量转成灰度图,统一大小尺寸,数据量在1000张图像以上。
- 负样本。不包含待检测目标的图片。例如除了车辆以外的物体,如树木、行人、路牌等 。负样本之间的尺寸大小随意,数据量尽量是正样本的3倍。
2、样本集合及描述文件
-
正样本。
正样本由 opencv_createsamples 应用程序创建。它们可以从带有对象的单个图像或从先前标记的图像的集合创建。提升过程使用它们来定义模型在尝试查找感兴趣的对象时实际应该查找的内容。该应用程序支持两种生成正样本数据集的方法。
- 您可以从单个正对象图像生成一堆正样本。
- 您可以自己提供所有正数,只需使用该工具将它们剪切出来,调整它们的大小并将它们放入 opencv 所需的二进制格式中。
虽然第一种方法对于固定对象(例如非常严格的徽标)效果很好,但对于不太严格的对象来说,它往往很快就会失败。在这种情况下,我们建议使用第二种方法。网络上的许多教程甚至指出,通过使用 opencv_createsamples 应用程序,100 个真实物体图像可以产生比 1000 个人工生成的正值更好的模型。但是,如果您决定采用第一种方法,请记住以下几点:
- 请注意,在将其提供给上述应用程序之前,您需要多个正样本,因为它仅应用透视变换。
- 如果您想要一个稳健的模型,请选取涵盖对象类中可能出现的各种类型的样本。例如,在相同面孔的情况下,您应该考虑不同的种族和年龄组、情绪,也许还有胡须风格。这也适用于使用第二种方法时。
第一种方法采用带有例如公司徽标的单个对象图像,并通过随机旋转对象、改变图像强度以及将图像放置在任意背景上,从给定对象图像创建大量正样本。随机性的数量和范围可以通过 opencv_createsamples 应用程序的命令行参数来控制。
opencv_createsamples -img /home/user/logo.png -bg /home/user/bg.txt -info /home/user/annotations.lst -pngoutput -maxxangle 0.1 -maxyangle 0.1 -maxzangle 0.1
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 <background_color_threshold>
-
-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.txt
信息数据info.txt:
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
[example - /data/annotations.txt] -
--images
(必需):包含对象图像的文件夹路径 [示例 - /data/testimages/] -
--maxWindowHeight
(可选):如果输入图像的高度大于此处给定的分辨率,请使用 调整图像大小以便于注释--resizeFactor
。 -
--resizeFactor
(可选):使用参数时用于调整输入图像大小的因子--maxWindowHeight
。
请注意,可选参数只能一起使用。可以使用的命令示例如下所示
opencv_annotation --annotations=/path/to/annotations/file.txt --images=/path/to/image/folder/ 路径必须使用绝对路径
示例:
opencv_annotation --annotations=/Users/wyy/opencv/opencv_data/annotations/posdata.txt --images=/Users/wyy/opencv/opencv_data/img/
此命令将启动一个窗口,其中包含第一个图像和将用于注释的鼠标光标。有关如何使用注释工具的视频可以在此处找到。基本上有几个击键可以触发一个动作。鼠标左键用于选择对象的第一个角,然后继续绘制直到您满意为止,并在第二次单击鼠标左键时停止。每次选择后,您有以下选择:
- 按
c
:确认注释,注释变为绿色并确认存储 - 按
d
:删除注释列表中的最后一个注释(方便删除错误的注释) - 按
n
:继续下一个图像 - 按
ESC
:将退出注释软件
最后,您将得到一个可用的注释文件,可以将其传递给-info
opencv_createsamples 的参数。
-
负样本。
负样本取自任意图像。这些图像不得包含检测到的对象。负样本被列举在一个特殊的文件中。它是一个文本文件,其中每行包含负样本图像的图像文件名(相对于描述文件的目录)。该文件必须手动创建。请注意,负样本和样本图像也称为背景样本或背景样本图像,并且在本文档中可以互换使用。所描述的图像可能具有不同的尺寸。但每个图像应该(但不一定)大于训练窗口大小,因为这些图像用于将负图像子采样到训练大小。
描述文件示例
目录结构
/img
img1.jpg
img2.jpg
bg.txt
文件bg.txt
img/img1.jpg
img/img2.jpg
3、实现样本数据采集
使用opencv_createsamples.exe创建样本
./opencv_createsamples -info posdata.txt -vec detect_number.vec -bg bg.txt -num 2 -w 280 -h 210
参数解释:
-info:posdata.txt的位置,可以直接使用绝对地址避免出错
-vec 生成vec文件的位置和名称
-bg negdata.txt的位置,可以直接使用绝对地址
-num 正样本的数量
-w -h 正样本的宽高
执行报错
Unable to open image: /Users/wyy/opencv/opencv_data//Users/wyy/opencv/opencv_data/img/img_0.jpg
libc++abi: terminating with uncaught exception of type cv::Exception: OpenCV(3.4.16) /Users/wyy/Downloads/opencv-3.4.16/modules/core/src/matrix.cpp:751: error: (-215:Assertion failed) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows in function 'Mat'
解决方法:执行图片路径错误,开始使用的是绝对路径
4、样本训练
下一步是基于事先准备的正负数据集对弱分类器的增强级联进行实际训练。
opencv_traincascade 应用程序的命令行参数按用途分组:
- 通用参数
- data <cascade_dir_name>: 分类器的输出路径,文件夹需要提前创建;
- vec <vec_file_name>: 正样本文件路径;
- bg <background_file_name>: 负样本文件路径;
-numStages <number_of_stages>: 级联训练的阶段数; - precalcValBufSize:预先计算的特征值的缓冲区大小(以 Mb 为单位);
- precalcIdxBufSize:预先计算的特征索引的缓冲区大小(以 Mb 为单位);
- numThreads <max_number_of_threads>:训练使用的最大线程数;
- acceptanceRatioBreakValue:用于确定模型应保持学习的精度以及何时停止。默认为-1,禁用此功能。
- 级联参数
- stageType <BOOST(默认)>: 阶段类型;
- featureType<{HAAR(默认), LBP}>: 特征类型:HAAR(Haar-like 特征),LBP(局部二进制模式);
- w <sampleWidth>:训练样本的宽度(以像素为单位);
- h <sampleHeight>:训练样本的高度(以像素为单位);
- 增强分类器参数
- bt <{DAB, RAB, LB, GAB(默认)}>:增强分类器的类型:DAB(Discrete AdaBoost),RAB (Real AdaBoost),LB(LogitBoost),GAB(Gentle AdaBoost);
- minHitRate:分类器每个阶段的最小期望命中率;
- maxFalseAlarmRate:分类器每个阶段的最大期望误差率;
- weightTrimRate:是否使用修正权重,建议值为 0.95;
- maxDepth <max_depth_of_weak_tree>:弱树的最大深度,建议值为1;
- maxWeakCount <max_weak_tree_count>:每个级联阶段的弱树的最大数量;
- Haar-like特征参数
- mode <BASIC(默认) | CORE | ALL>:选择训练中使用的 Haar 特征集的类型。其中BASIC 仅使用直立功能,而 ALL 使用直立和 45 度旋转功能集;
训练完成,您可以测试您的级联分类器!
./opencv_traincascade -data data -vec detect_number.vec -bg negdata.txt -numPos 850 -numNeg 4666 -numStages 20 -featureType HAAR -w 32 -h 24
参数解释:
-data 存放训练好的xml文件的文件夹,这个一定要事先创建好
-vec 之前生成vec文件
-bg negdata.txt的位置
-numPos 正样本的数量
-numNeg 负样本的数量
-numStages 训练步数
-featureType 特征类型,有三种,HAAR最常用
-w -h 正样本的宽高即是上步生成的样本宽高
5、生成级联分类数据(xml)
如下图所示:cascade.xml 即为级联分类器最终文件
[图片上传失败...(image-c3a84f-1697081201055)]
6、报错及解决
执行命令报错
./opencv_traincascade -data data -vec detect_number.vec -bg bg.txt -numPos 11 -numNeg 4 -numStages 12 -w 48 -h 48
- data/params.xml can not be opened.
Parameters can not be written, because file data/params.xml can not be opened.
解决方法:执行目录下没有data目录,需要新建-data后面的输出目录
- -215:Assertion failed
ibc++abi: terminating with uncaught exception of type cv::Exception: OpenCV(3.4.16) /Users/wyy/Downloads/opencv-3.4.16/apps/traincascade/imagestorage.cpp:153: error: (-215:Assertion failed) _img.rows * _img.cols == vecSize in function 'get'
解决方法:训练样本的宽高要和生成样本的宽高一致。
- 参数错误
./opencv_traincascade -data data -vec detect_number.vec -bg bg.txt -numPos 11 -numNeg 4 -numStages 20 HAAR -w 48 -h 48 -minHitRate 0.995 -maxFalseAlarmRate 0.45
zsh: segmentation fault ./opencv_traincascade -data data -vec detect_number.vec -bg bg.txt -numPos 11
解决方法: HAAR前面添加-featureType
三、可视化级联分类器
可视化级联分类器用于在训练过程中,看到实时训练数据视图。OpenCV提供opencv_visualisation应用程序,相关命令如下:
- image(必选): 图像模型的路径;
- model(必选): 训练模型的路径;
- data(可选): 如果提供提前创建的数据文件夹,将存储每个阶段结果;
命令行示例如下:
./opencv_visualisation --image=img/img_01.jpg --model=data/cascade.xml --data=data/result/
当前可视化工具的一些局限性
- 仅处理使用 opencv_traincascade 工具训练的级联分类器模型,包含树桩作为决策树 [默认设置]。
- 提供的图像需要是具有原始模型尺寸的示例窗口,并传递给参数--image。