前面我们已经得到了一个强分类器H(x),我们知道它是有缺陷的,它的Recall=0.995,FalseAlarmRate=0.5,也就说它能办让99.5%的人脸通过,同时也有50%的非人脸也能通过。
有了强分类器我们得到一条结论:
如果一个样本Xi,强分类器H(Xi) < ST,那么它不是人脸。
那如果H(Xi) > ST呢?答案是还不能确定,需要进一步观察。
就好像你拿一个淘金的筛子去淘金,这个筛子把绝大部分的金子都留在上面,筛去了一部分砂砾,也有相当一部分沙子和金子混在一起留在筛子里。为了提纯金子,靠这个筛子看来是没办法了。解决的办法就是换一个别筛子继续处理。
也就是说还需要训练一个类似的强分类器H2,如果一个样本通过了第一个强分类器H1的筛选,再用H2筛一遍,如果H2还筛不干净,继续训练H3,H4...Hs,直到最后的虚警率低于我们的要求。
级联是如何实现的?
首先明确我们的目标,我们已经训练的一个强分类器H1(x),它的recall满足要求,问题是虚警率FAR太高,因此下一步的目标就是要降低虚警率。
前面我们从收集的正样本集PX和负样本集NX上训练得到一个强分类器H1,现在该如何去训练一个新的强分类器H2呢?
显然使用原训练集是没有帮助的,会得到与H1一样的强分类器。这是我们希望得到一个新的数据集,其中包含足够多的正样本,这些正样本能够通过前面的强分类器,负样本集中包含足够多的负样本,而且这些负样本都是前面的强分类器处理不了的case,也就是他们判断为正样本的负样本。
如此看来,对于正样本集,我们可以直接从PX中选取能够保留下来的样本组成,也就说正样本集基本不变,除了少数被之前的强分类器判别为负。
关键是负样本集,因为原来的NX上有近一半都被Reject了,数据集变小了很多,需要补充新的负样本数据。好在这一点不难办到,我们可以搜集大量的不包含人脸的图片,然后从中扣取W*H的小图作为负样本。
有了新的数据集NX’,PX’训练强分类器的过程跟之前完全一样。
因此强分类器级联之所以有效,是因为下一个层级的负样本数据集都是由能够通过前面所有层级的负样本(产生虚警的样本)构成的,新的强分类器能够处理原先处理不了的负样本,所以新的层级加入后能够进一步降低虚警率。与此同时新的强分类器的引入会进一步降低Recall。
假设我们训练了H1,…Hs个强分类器,每个强分类器Recall都设置为rc=0.995,FAR为falsealarm=0.5。拿到一个新的样本Xi,如何判别它是否为人脸呢?
首先交给H1,如果H1判别为负,则判断Xi为非人脸。
否则,将Xi交给H2,同样的如果判别负,则给出结论非人脸。
否则继续交给下一个强分类器。
如果直到最后一个强分类器Hs输出为+1,则给出结论,Xi属于人脸!
总结一下,任何一个强分类器判别为负样本,Xi就会判别为负样本。而一个正样本需要通过全部强分类器的筛选才最终被判别为正样本。
我们把这样强分类器的级联形成的分类器叫做级联分类器,Cascade classifier。显然最终级联分类器的Recall为强分类器Recall的乘积,虚警率FAR也为强分类器FAR的乘积:
Recall=pow(rc,s)
FAR=(falsealarm,s)
参数rc,falsealarm,s根据我们的实际需要来合理选取。s越大最终分类器的召回率越低,虚警率也越低。
至此,关于如何检测人脸的原理部分就说到这里了。后面我们会结合opencv的源码继续详解如何编程实现。