人脸检测一种主流的方法就是类haar+adaboosting,opencv中也是用的这种方法。这种方法可以推广到刚性物体的检测,前提是要训练好级联分类器(比如说用类haar特征),一旦训练数据弄好了,直接调用opencv中的类CascadeClassifier,用它的几个简单的成员函数就可以完成检测功能。
Haar分类器的概念
以 Haar 特征分类器为基础的对象检测技术是一种非常有效的对象检测技术(2001 年 Paul_Viola 和 Michael_Jones 提出)。它是基于机器学习的, 通过使用大量的正负样本图像训练得到一个 cascade_function,最后再用它 来做对象检测。 现在我们来学习面部检测。开始时,算法需要大量的正样本图像(面部图像)和负样本图像(不含面部的图像)来训练分类器。我们需要从其中提取特 征。下图中的 Haar 特征会被使用。它们就像我们的卷积核。每一个特征是一 个值,这个值等于黑色矩形中的像素值之后减去白色矩形中的像素值之和。
使用所有可能的核来计算足够多的特征。(想象一下这需要多少计算量?仅仅是一个 24x24 的窗口就有 160000 个特征)。对于每一个特征的计算我们 好需要计算白色和黑色矩形内的像素和。为了解决这个问题,作者引入了积分 图像,这可以大大的简化求和运算,对于任何一个区域的像素和只需要对积分 图像上的四个像素操作即可。非常漂亮,它可以使运算速度飞快
但是在我们计算得到的所有的这些特征中,大多数是不相关的。如下图所示。上边一行显示了两个好的特征,第一个特征看上去是对眼部周围区域的描述,因为眼睛总是比鼻子黑一些。第二个特征是描述的是眼睛比鼻梁要黑一些。但是如果把这两个窗口放到脸颊的话,就一点都不相关。那么我们怎样从超过 160000+ 个特征中选出最好的特征呢?使用 Adaboost。
为了达到这个目的,我们将每一个特征应用于所有的训练图像。对于每一个特征,我们要找到它能够区分出正样本和负样本的最佳阈值。但是很明显, 这会产生错误或者错误分类。我们要选取错误率最低的特征,这说明它们是检测面部和非面部图像最好的特征。(这个过程其实不像我们说的这么简单。在开始时每一张图像都具有相同的权重,每一次分类之后,被错分的图像的权重会增大。同样的过程会被再做一遍。然后我们又得到新的错误率和新的权重。重复执行这个过程知道到达要求的准确率或者错误率或者要求数目的特征找到)。 最终的分类器是这些弱分类器的加权和。之所以成为弱分类器是应为只是用这些分类器不足以对图像进行分类,但是与其他的分类器联合起来就是一个 很强的分类器了。文章中说 200 个特征就能够提供 95% 的准确度了。他们最 后使用 6000 个特征。(从 160000 减到 6000,效果显著呀!)。 现在你有一幅图像,对每一个 24x24 的窗口使用这 6000 个特征来做检查,看它是不是面部。这是不是很低效很耗时呢?的确如此,但作者有更好的 解决方法。 在一副图像中大多数区域是非面部区域。所以最好有一个简单的方法来证明这个窗口不是面部区域,如果不是就直接抛弃,不用对它再做处理。而不是 集中在研究这个区域是不是面部。按照这种方法我们可以在可能是面部的区域多花点时间。 为了达到这个目的作者提出了级联分类器的概念。不是在一开始就对窗口进行这 6000 个特征测试,将这些特征分成不同组。在不同的分类阶段逐个使 用。(通常前面很少的几个阶段使用较少的特征检测)。如果一个窗口第一阶段 的检测都过不了就可以直接放弃后面的测试了,如果它通过了就进入第二阶段 的检测。如果一个窗口经过了所有的测试,那么这个窗口就被认为是面部区域。 这个计划是不是很帅!!! 作者将 6000 多个特征分为 38 个阶段,前五个阶段的特征数分别为 1,10,25,25 和 50。(上图中的两个特征其实就是从 Adaboost 获得的最好 特征)。
Haar级联器的数据
OpenCV的源码
sources\data\haarcascades
复制到你的工程
静态图像人脸检测
|
|
scaleFactor:每次图像尺寸减小的比例;minNeighbors每一个目标至少要被检测到n次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸)
Python: cv2.CascadeClassifier.detectMultiScale(image[, scaleFactor[, minNeighbors[, flags[, minSize[, maxSize]]]]]) → objects
Parameters:
- cascade – Haar classifier cascade (OpenCV 1.x API only). It can be loaded from XML or YAML file using Load(). When the cascade is not needed anymore, release it using cvReleaseHaarClassifierCascade(&cascade).
- image – Matrix of the type CV_8U containing an image where objects are detected.
- objects – Vector of rectangles where each rectangle contains the detected object.
- scaleFactor – Parameter specifying how much the image size is reduced at each image scale.
- minNeighbors – Parameter specifying how many neighbors each candidate rectangle should have to retain it.
- flags – Parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade.
- minSize – Minimum possible object size. Objects smaller than that are ignored.
- maxSize – Maximum possible object size. Objects larger than that are ignored.
视频中的人脸检测
123456789101112131415161718192021222324# coding:utf-8import cv2def detect():face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')camera = cv2.VideoCapture(1)while True:ret, frame = camera.read()gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)faces = face_cascade.detectMultiScale(gray, 1.1, 5)for (x, y, w, h) in faces:img = cv2.rectangle(frame, (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, 1.3, 6, 0, (40, 40))for (ex, ey, ew, eh) in eyes:cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (255, 255, 255), 2)cv2.imshow("camera", frame)if cv2.waitKey(1000 / 12) & 0xff == ord("q"):breakcamera.release()cv2.destroyAllWindows()if __name__ == "__main__":detect()
不上图