OpenCV中的Haar+Adaboost(六):minHitRate与maxFalseAlarm

来源:互联网 发布:图书借阅管理系统 php 编辑:程序博客网 时间:2024/05/20 02:30

在之前的文章中,分别讲解了Haar特征,强弱分类器组合形式,以及GAB。那么在了解这些内容的基础上,本节开始正式讲解OpenCV Adaboost训练过程。

缩进需要再次说明的是,本系列文章讲解的是opencv中的opencv_traincascade.exe程序的实现方法,并不代表仅只有此一种实现方法。

-------------------------------------------

缩进在了解训练过程之前,还需要分析一些和训练相关的原理。


1 precision与recall

缩进对于所有的监督学习(supervised learning),都需要一组正样本(positive samples)和负样本(negative samples)。以训练人脸检测器为例,人脸图片即正样本,所有的非人脸区域即为负样本。对于一组positive samples和negative samples,经过检测器后,会有以下4种情况:

positive sample会产生:

  1. TP(true positive),即positive sample被检测器判定为目标
  2. FN(false negative),即positive samples被检测器判断为非目标,相当于检测器“漏掉”了目标

negative sample会产生:

  1. TN(true negative),即negative sample被检测器判定为非目标
  2. FP(false positive),即negative sample被检测器判定为目标,相当于产生了“误检” or “虚警”

也就是说,在实际中不仅关心是否检测错误,更关心的是把“什么”检测成了“什么”,分类更加细致。借用知乎网友Charles Xiao的一张图:

图1

其中论文中常见的两个指标:

precision = tp / (tp + fp)

recall = tp / (tp + fn)

一般在实际应用中,希望precision和recall都很高。还是以人脸检测为例,不妨假设图中有10个人脸。

  1. 若检测器只发现了1个人脸,此时precision=1虽然很高,但是recall=0.1非常低
  2. 若检测器发现了50个人脸(假设包含了10个真人脸),此时recall=1很高,但是precision=10/50=0.2很低

所以只有precision和recall都比较高时,讨论检测器的参数才有意义。但是现实情况中鱼和熊掌不可兼得,很难做到precision和recall都很高,所以会绘制precision-recall曲线(简称PR曲线)评估检测器的意义。由于这不是本文的主要内容,不再介绍,等有机会我会补上一篇介绍。


2 hitRate与falseAlarm

图2

缩进而在Adaboost训练过程中,我们更关心的是minHitRate和maxFalseAlarmRate参数,如图2红框中。在OpenCV的boost.cpp中CvCascadeBoost::isErrDesired()函数,对每一个stage有如下定义:

[cpp] view plain copy
  1. float hitRate = ((float) numPosTrue) / ((float) numPos);  
  2.   
  3. float falseAlarm = ((float) numFalse) / ((float) numNeg);  
换个表达方式:

hitRate = tp / (tp + fn) = recall

falseAlarm = fp / (tn + fp)

这里hitRate称为“命中率”,度量检测器对正样本的通过能力,显然越接近1越好;而falseAlarm称为“虚警率”,度量检测器对负样本的通过能力,显然越接近0越好。


图3 adaboost级联结构

考虑到Haar+Adaboost的stage间“串联”形式(如图3,参考本系列文章三),stageNum个stage串联后,已知每个stage的hitRate(i)和falseAlarm(i),整个检测器最终的hitRate和falseAlarmRate为:

hitRate = hitRate(1) x hitRate(2) x ..... x hitRate(stageNum) = ∏hitRate(i)

falseAlarmRate = falseAlarm(1) xfalseAlarm(2)x ...... x falseAlarm(stageNum) = ∏hitRate(i)

而∏表示连乘符号。那么:

1.为了让检测器最终的hitRate接近1,每一个stage的hitRate(i)必须很大,即每一个stage的正样本通过率必须非常高。

2. 同理,为了让检测器最终的falseAlarmRate接近0,每一个stage的falseAlarm(i)必须很小,即每一个stage的负样本虚警率必须比较低。

从图2中可以看到默认minHitRate = 0.995,默认maxFalseAlarmRate = 0.5。假设stageNum = 20时,最终检测器有:

hitRate  minHitRate ^ stageNum = 0.995 ^ 20 = 0.904610....

falseAlarmRate  maxFalseAlarmRate ^ stageNum = 0.5 ^ 20 = 0.00000095...

然后换一组参数,当minHitRate = 0.9,maxFalseAlarmRate = 0.6时,每一个stage的hitRate从0.995变为0.9,最终的检测器hitRate竟然掉到了0.12,Amazing!

hitRate  0.9 ^ 20 = 0.12157...

falseAlarmRate ≈ 0.6 ^ 20 = 0.000036...

由此看出每一个stage的minHitRate必须非常高(>=0.995)!而maxFalseAlarmRate则相对“温和”一些。

总结一下:

1. 由于串联的stage数量很多,minHitRate必须非常接近1,才能保证最终检测器有较好的recall;

2. falseAlarmRate相当于对检测器的precision作了约束;

3. 相对于maxFalseAlarmRate,minHitRate更加敏感。


-------------------------------------------------------------------------------
插入一段:前段时间在知乎翻到一个问题,结合上述内容恰好可以解释。

-------------------------------------------------------------------------------

本节介绍了一些和训练相关的基本的参数,下节以此为基础介绍OpenCV中分类器训练方法。

阅读全文
0 0
原创粉丝点击