12.1. 基于Haar级联的人脸检测

12.1.1. 目标

在这次会议上,

  • 我们将看到使用基于Haar特征的级联分类器进行人脸检测的基础知识

  • 我们将把它推广到眼睛检测等领域。

12.1.2. 基础

基于Haar特征的级联分类器的目标检测是Paul Viola和Michael Jones在2001年的论文《利用简单特征的增强级联快速目标检测》中提出的一种有效的目标检测方法。这是一种基于机器学习的方法,其中一个级联函数是从许多正面和负面图像中训练出来的。然后,它被用于检测其他图像中的对象。

我们将在这里进行面部检测。该算法首先需要大量的正图像(人脸图像)和负图像(无人脸图像)来训练分类器。然后我们需要从中提取特征。为此,使用下图所示的haar特征。它们就像我们的卷积核。每一个特征都是一个单独的值,从黑矩形下的像素和中减去白矩形下的像素和。

现在,每个内核的所有可能大小和位置都被用来计算大量的特性。(想象一下它需要多少计算?即使是一个24x24窗口,也会产生超过160000个功能)。对于每一个特征计算,我们需要找到在白色和黑色矩形下的像素和。为了解决这个问题,他们引入了积分图像。它将像素和(像素的数量可能有多大)的计算简化为仅涉及四个像素的操作。很好,不是吗?它让事情变得非常快。

但在我们计算的所有这些特征中,大多数都是无关的。例如,考虑下面的图片。最上面一排显示了两个很好的特性。选定的第一个特征似乎集中在眼睛区域通常比鼻子和脸颊区域暗的属性上。选择的第二个特征依赖于眼睛比鼻梁暗的属性。但同样的窗户在脸颊或其他任何地方都是无关紧要的。那么我们如何从160000多个功能中选择最好的功能呢?它是通过 Adaboost公司 .

为此,我们将每个特征应用于所有训练图像。对于每一个特征,它都会找到最佳的阈值,将人脸分为正反两类。但显然,会有错误或错误的分类。我们选择错误率最小的特征,这意味着它们是对人脸和非人脸图像进行最佳分类的特征。(过程并不像这样简单。每幅图像在开始时都有一个相等的权重。每次分类后,错误分类图像的权重都会增加。然后,同样的过程再次完成。计算新的错误率。还有新的重量。该过程将继续进行,直到达到所需的精度或错误率或找到所需数量的特征)。

最终分类器是这些弱分类器的加权和。它之所以被称为弱分类器,是因为它不能单独对图像进行分类,而是与其他分类器一起形成一个强分类器。文章说,即使是200个特征也能提供95%的检测准确率。他们的最终设置大约有6000个功能。(想象一下从160000多个功能减少到6000个功能。这是一个很大的收获)。

所以现在你拍一张照片。每个24x24窗口。应用6000个功能。看看是不是脸。真 的。。真 的。。是不是有点低效和费时?是的,是的。作者对此有一个很好的解决方案。

在图像中,大部分图像区域都是非人脸区域。因此,最好有一个简单的方法来检查窗口是否不是面区域。如果没有,就一次性丢弃。别再处理了。取而代之的是把注意力集中在有脸的地方。这样,我们可以找到更多的时间来检查可能的面部区域。

为此,他们引入了 分类器级联 . 不要在窗口上应用所有6000个特征,而是将这些特征分组到分类器的不同阶段,然后逐个应用。(通常前几个阶段包含的特征数量很少)。如果窗口在第一阶段失败,请丢弃它。我们不考虑它的其他特性。如果通过,则应用功能的第二阶段并继续该过程。通过所有阶段的窗口是一个面区域。计划怎么样!!!

作者的探测器有6000多个特征,38个阶段,前5个阶段有1、10、25、25和50个特征。(上图中的两个特征实际上是从Adaboost获得的最好的两个特征)。根据作者的说法,平均每个子窗口评估6000+中的10个特征。

所以这是一个简单直观的解释,如何维奥拉琼斯面部检测工作。阅读文章了解更多细节,或者查看附加参考资料部分中的参考资料。

12.1.3. OpenCV中的Haar级联检测

OpenCV配有一个训练器和探测器。如果你想为汽车、飞机等任何物体训练你自己的分类器,你可以使用OpenCV来创建一个。详情如下: Cascade Classifier Training.

在这里我们将处理检测问题。OpenCV已经包含了许多用于人脸、眼睛、微笑等的预先训练过的分类器 opencv/data/haarcascades/ 文件夹。让我们用OpenCV创建面部和眼睛检测器。

首先,我们需要加载所需的XML分类器。然后以灰度模式加载输入图像(或视频)。

>>> import numpy as np
>>> import cv2
>>>
>>> face_cascade = cv2.CascadeClassifier('/cvdata/haarcascade_frontalface_default.xml')
>>> eye_cascade = cv2.CascadeClassifier('/cvdata/haarcascade_eye.xml')
>>>
>>> img = cv2.imread('/cvdata/sachin.jpg')
>>> gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

现在我们在图像中找到人脸。如果找到面,它将检测到的面的位置返回为Rect(x,y,w,h)。一旦我们得到这些位置,我们就可以为人脸创建一个ROI,并对这个ROI应用眼睛检测(因为眼睛总是在脸上!!!)。

>>> faces = face_cascade.detectMultiScale(gray, 1.3, 5)
>>> for (x,y,w,h) in faces:
>>>     img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
>>>     roi_gray = gray[y:y+h, x:x+w]
>>>     roi_color = img[y:y+h, x:x+w]
>>>     eyes = eye_cascade.detectMultiScale(roi_gray)
>>>     for (ex,ey,ew,eh) in eyes:
>>>         cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
>>> %matplotlib inline
>>> import matplotlib.pyplot as plt
>>> plt.imshow(img)
<matplotlib.image.AxesImage at 0x7fcdc0ab5048>
../_images/sec01-face-detection_4_1.png
>>>
>>> # cv2.imshow('img',img)
>>> # cv2.waitKey(0)
>>> # cv2.destroyAllWindows()

结果如下:

12.1.4. 额外资源

  1. 视频讲座 Face Detection and Tracking

  2. 一个有趣的关于人脸检测的访谈 Adam Harvey

12.1.5. 练习