OpenCV 使用的 Object detection 技术称为 Cascade Classifier for Object Detection ,是一种属于 boosted cascade of weak classifiers 的方法,也就是将数个弱分类器串联起来再得出最佳的分类结果。其实最早整合到 OpenCV 并支持的分类特征是哈尔特征(Haar-like features),后来加入了 LBP ( Local Binary Pattern)以及 HOG( Histogram Of Gradient),不过可惜的是 HOG 在 3.x 后由于某些技术问题被取消了。

Boosting 的中心思想在于「三个臭皮匠胜过一个诸葛亮」,主要是将大量的弱分类器(分类效果仅比随机好一点)逐步训练成一个较强的分类器,透过对每个弱分类器分类错误的部份持续投入学习,最后形成一个超强的分类器。

举例来说,我们熟知的 Spam mails 检测,就是一种 Boosting 的概念,拆开,每一条 spam check rule 都是弱分类器,仅对一小部份的垃圾邮件有效,但是把数以百计的 rules 串连起来,便能打造一个滴水不漏的垃圾邮件防堵系统!

在机器学习中,有很多分类器便应用了 Boosting 的方法,例如 AdaBoost(Adaptive Boosting)、Gradient Tree Boosting、XGBoost 等, 而 OpenCV 内建的 Cascade Classifier for Object Detection,正是应用了AdaBoost。

新版 OpenCV 对于 Cascade Classifier 的支持

可惜的是,OpenCV 4.x 版后不再支持 Cascade Classifier 的训练,因此目前在 4.x 版的 OpenCV 代码中,无法看见诸如 opencv_createsamples、opencv_traincascade 等程序,官方的说法是近几年流行的 ML、DL 效果更佳,鉴于使用者逐渐减少,决定不再包入相关的训练程序在源码中。

不过事实上目前还是有相当多的使用者对于 cascade classifier 有强烈的需求,因为它使用方便、侦测速度快,常让人包容误报率高和训练复杂的缺点,因此有传闻官方可能会在下一版本的 OpenCV 中再度支持。

训练猫脸侦测器

特意编写了一套工具程序可快速方便地进行 Cascade Classifier 的训练,以下以猫脸侦测示范如何使用这个工具制作自己的 Cascade Classifier。

搜集照片和标记

1. 先从网络上下载一些猫的照片,本例中下载了 126 张。




java opencv 分类器训练 识别文字 opencv分类器原理_opencv训练自己的分类器


2. 使用 labelImg 进行标记:由于猫脸区域不像人脸那么明确,因此在框选时选择从两眼外侧(不包含耳朵)开始直到下巴的区域。


java opencv 分类器训练 识别文字 opencv分类器原理_垃圾邮件_02


准备 dataset

此步骤将产生训练时需要的positives(正向图片,即标记的猫脸)以及 negatives(负向图片,即没有猫脸的图片)。

1. 所有相片及标记好的 label 分别置于 images 及 labels 的文件夹中。

2. 执行 1_labels_to_pos_neg_imgs.py:此程序的目的是将所有相片中的标记框取出,另外存到一个folder 下,这些图片称为 positives,图片中不含标记框的其它区域则存到 neg_bg 资料夹中,这些与猫脸无关的图片称为 negatives。1_labels_to_pos_neg_imgs.py 的参数如下,您只要修改参数的内容即可:

#标记档的pathxmlFolder = “H:workingcascade_cat_facevoc_datasetlabels”#图片档的pathimgFolder = “H:workingcascade_cat_facevoc_datasetimages”#要取出的标记名称(class name)labelName = “catface”#项目目录,所有产生的档案或目录皆会存于此projFolder = “H:workingcascade_cat_facecascade_training”#训练的图片大小(建议不要太大)outputSize = (54, 45)#产生的训练图片类型imageKeepType = “jpg”#去除标记区域的图片,是否要作为negative图片?generateNegativeSource = True

执行成功后,会产生以下两个目录:positives(正向图片),含有猫脸标记的图片;neg_bg(负向图片),不含猫脸标记的图片(我把有猫脸的区域以黑色色块取代,就能作为负面图片来使用)。


java opencv 分类器训练 识别文字 opencv分类器原理_opencv训练自己的分类器_03

positives


java opencv 分类器训练 识别文字 opencv分类器原理_opencv训练自己的分类器_04

negatives


3. 执行 2_generate-negatives.py:本程序使用 sliding window 的方式,将 neg_bg 文件夹下的相片切裁为指定大小的 negatives 图片,并产生一个 negatives.info 文件。

#项目目录,所有产生的档案或目录皆会存于此projFolder = “H:workingcascade_cat_facecascade_training”#sliding window移动距离movePixels = 80#sliding window时图片依次的缩小比例resizeScale = 0.5#裁切出的图片大小negSize = (54, 45)#载切后储存的图片格式imageKeepType = “jpg”#neg_bg folder下的图片要不要先缩小为指定尺寸? 0–> keep the sameresize_org_w = 0#要产生多少负向的图片?imagesCount = 8000

negatives 资料夹内容:


java opencv 分类器训练 识别文字 opencv分类器原理_垃圾邮件_05


negatives.info文件内容:

H:workingcascade_cat_facecascade_trainingegatives1580366317.81161742.jpg

H:workingcascade_cat_facecascade_trainingegatives1580366317.81961253.jpg

H:workingcascade_cat_facecascade_trainingegatives1580366317.83462724.jpg

H:workingcascade_cat_facecascade_trainingegatives1580366317.84162245.jpg

H:workingcascade_cat_facecascade_trainingegatives1580366317.8586116.jpg

H:workingcascade_cat_facecascade_trainingegatives1580366317.86569797.jpg

4. 执行 3_augmentation.py:本程序使用 augmentation 强化资料的方式产生更多正向图片,新增加的图片将放置于 aug_positives 文件夹下。

#项目目录,所有产生的文档或目录皆会存于此projFolder = “H:workingcascade_cat_facecascade_training”#产生的正向图片大小outputSize = (54, 45)#产生的图片格式imageKeepType = “jpg”#每一个正向图片要产生出几张新图片?numAugment = 3#Augmentation的设定aug_whitening = Falseaug_rotation = 16aug_w_shift = 0.1aug_h_shift = 0.1aug_shear = 0.1aug_zoom = 0.05aug_h_flip = Trueaug_v_flip = Falseaug_fillmode = “nearest”

产生的图片如下,原本仅有 243 张,但通过 augmentation 增加了 929 张。


java opencv 分类器训练 识别文字 opencv分类器原理_图片格式_06


5. 执行 4_add_aug_positives_to_list.py:将前一步所产生的图片放到 positives.info 文件,其内容截录如下。

positives/aug__0_4419.jpg 1 0 0 54 45

positives/aug__0_584.jpg 1 0 0 54 45

positives/aug__0_5614.jpg 1 0 0 54 45

positives/aug__0_402.jpg 1 0 0 54 45

positives/aug__0_7285.jpg 1 0 0 54 45

positives/aug__0_710.jpg 1 0 0 54 45

positives/aug__0_4390.jpg 1 0 0 54 45

最终待训练用的文件夹及其下文件如下:


java opencv 分类器训练 识别文字 opencv分类器原理_图片格式_07


产生训练用的 VEC 档

由于 Cascade Classifier 不能直接读取图片,我们必须转为 VEC 才能开始训练。

1. 进入项目目录:H:workingcascade_cat_facecascade_training

cd H:workingcascade_cat_facecascade_training

2. 执行 opencv_createsamples.exe

H:opencvbuildx64vc15binopencv_createsamples.exe -info positives.info -vec samples.vec -w 54 -h 45 -num 1790

若出现如下方的 error message,表示某个图文件有问题,建议直接从 positives.info 列表中删除该图,例如下方第 229 行的图文件有问题,直接删除该行。


java opencv 分类器训练 识别文字 opencv分类器原理_OpenCV_08


再执行一次 opencv_createsamples.exe 便可成功转换,最后是如下画面:


java opencv 分类器训练 识别文字 opencv分类器原理_图片格式_09


开始训练

1. 进入项目目录:H:workingcascade_cat_facecascade_training

cd H:workingcascade_cat_facecascade_training

2. 执行下方的指令:

H:opencvbuildx64vc15binopencv_traincascade.exe -data H:workingcascade_cat_facecascade_training -vec samples.vec -bg negatives.info -numPos 1700 -numNeg 7000 -numStages 8 -minHitRate 0.995 -maxFalseAlarmRate 0.3 -w 54 -h 45 -featureType LBP


java opencv 分类器训练 识别文字 opencv分类器原理_图片格式_10


3. 执行重点

(1)训练 stange 的数目由 -numStages 指定。

(2)HR(Hit Rate,侦测到物件)、FA(False Alarm,错误侦测到物件,即误判)此两个值分别由 -minHitRate 和 -maxFalseAlarmRate 指定,训练结果满足这两个值表示该 Stage 结束。

(3)-featureType可指定为HAAR 或 LBP,目前比较流行的是 LBP,训练速度较快且侦测效果不亚于 HAAR。


java opencv 分类器训练 识别文字 opencv分类器原理_图片格式_11


java opencv 分类器训练 识别文字 opencv分类器原理_垃圾邮件_12


java opencv 分类器训练 识别文字 opencv分类器原理_垃圾邮件_13


上图中可看出训练时间相当长,但如果将 -featureType 改为 HAAR,则训练时间会比 LBP 要多出好几倍!

训练结果(LBP)

这次测试总共标记了 126 张相片(约有 241 张猫脸正样本),另外通过资料强化扩增到 1,794 张,再搭配 7,059 张负样本进行了 OpenCV Cascade Classifier 的 LBP 训练,最后训练了 7 个阶段,总训练时间为 5 小时 36 分 41 秒。

另外找了 11 张相片作为 test 图片,使用训练完成所产生的 cascade xml 测试其效果如下,若能继续增加更多的猫脸正样本,应该可提高识别的效果。

效果还不错


java opencv 分类器训练 识别文字 opencv分类器原理_opencv训练自己的分类器_14


java opencv 分类器训练 识别文字 opencv分类器原理_垃圾邮件_15


java opencv 分类器训练 识别文字 opencv分类器原理_图片格式_16


只侦测出部分


java opencv 分类器训练 识别文字 opencv分类器原理_opencv训练自己的分类器_17


java opencv 分类器训练 识别文字 opencv分类器原理_opencv训练自己的分类器_18


Bounding box 大小位置有待加强


java opencv 分类器训练 识别文字 opencv分类器原理_图片格式_19


java opencv 分类器训练 识别文字 opencv分类器原理_垃圾邮件_20


False Alarm


java opencv 分类器训练 识别文字 opencv分类器原理_OpenCV_21


作者:曾成训(CH.TSENG)