本文我们会讲讲怎样利用不到 25 行 Python 代码和开源库 OpenCV,以很简单的方式实现人脸识别。
在正式开始前,先提以下两点小小的建议:先别急着跳到代码部分,最好在前文理解一下代码是干什么的。
确保你使用的是OpenCV v2。
OpenCV
OpenCV 是计算机视觉领域最受欢迎的开源库,起初它由 C/C ++ 编写,现在用 Python 也能使用。
OpenCV 可以使用机器学习算法搜索图像中的人脸。由于人脸比较复杂,所以并没有一种简单的测试可以告诉我们它是否发现了人脸。但是,算法能够匹配到数千个很小的模式和特征。算法会将识别人脸的任务分解为几千个非常非常小的任务,像这种很小的任务,解决起来就比较容易了。这样的微小任务就被称为分类器。
对于人脸这样的物体,我们可能会有6千多个分类器,它们全都和检测到的人脸匹配(当然是在有限误差内)。但是这样也存在一个问题:对于人脸检测来说,算法从图像的左上角开始,一点点向下移动,经过一个个数据小方块,然后挨个查看它们,不断地问“这是个人脸吗?”···“这是个人脸吗?”···“这是个人脸吗?”因为每个小方块都要进行6千多次测试,那么我们就要进行数百万次计算,这么下去...电脑估计都要歇菜了。
为了解决这个问题,OpenCV 使用了 cascades 的概念?什么是 cascades?如果查字典,会告诉你 cascades 意为“瀑布或一系列的瀑布流”。
和瀑布流一样,OpenCV cascades 会把人脸识别问题分解为很多个阶段。对于每个数据小方块,它会进行非常粗略和迅速的测试。如果测试通过,会进一步进行更详细的测试,以此类推。算法会有 30 到 50 个这样的阶段,或者说 cascades,在所有阶段都通过测试时,就能确认识别的是人脸了。
它的优点是,在开始几个阶段内,若不是人脸,图像大部分就会返回否定结果,这意味着算法就不用再浪费时间测试全部6千余个特征。因此,现在我们完全能够实时做到人脸检测,不用花费几个小时。
Cascades 实践
虽然理论听上去有些复杂,但实践起来并不难。Cascades 就是一堆 XML 文件,包含了用于检测物体的 OpenCV 数据。用你想使用的 cascades 初始化你的代码后,它就能为你工作了。
由于人脸检测是一种常见的任务,所以 OpenCV 内置了很多 cascades,用于检测人体身上的很多部位,比如人脸、眼睛和手指等等。也能检测人体之外的物体,比如此前就有人开发了能识别香蕉的程序,可以帮水果店追踪偷拿香蕉的人!
安装 OpenCV
首先,你需要针对你的操作系统,找到正确的设置文件。
我发现安装 OpenCV 是识别人脸任务中最难的部分。如果你遇到了奇怪的很难解释的错误,那可能是因为库不兼容,操作系统是 32位/64位 等等此类的问题。我觉得使用 Linux 虚拟机从头安装 OpenCV 最容易。
等完成安装后,就可以用如下 Python 会话测试一下 OpenCV 能否工作:
>>> import cv2
>>>
如果没出什么问题,就接着往下看吧。
理解代码
这是整个代码库(https://github.com/shantnu/FaceDetect/),你可以从上面把代码下载下来。我们来解析一下代码。找到face_detect.py脚本,ABBA.png图像和haarcascade_frontalface_default.xml文件。
# 获取用户提供的值
imagePath = sys.argv[1]
cascPath = sys.argv[2]
你首先将图像和 cascade 名称作为命令行属性传入。我们会使用 abba 图像和默认 cascades 检测 OpenCV 提供的人脸。
# 创建 haar cascade
faceCascade =
cv2.CascadeClassifier(cascPath)
现在我们创建 cascade,以我们的人脸 cascade 将其初始化。这里会将人脸 cascade 加载到内存中,因此它是随时可用的。记住,cascade 只是一个包含了检测人脸的数据的 xml 文件。
# 读取图像
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image,
cv2.COLOR_BGR2GRAY)
这里,我们读取图像,将其转换为灰度图。OpenCV 中的很多操作都是以灰度图完成的。
# 检测图像中的人脸
faces =
faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags = cv2.cv.CV_HAAR_SCALE_IMAGE
)
该函数会检测实际的人脸,也是我们代码的核心部分,我们看看具体操作:
这里的detectMultiScale函数是一个能够检测物体的通用函数。因为我们在人脸cascade里调用它,那么它的目标就是检测人脸了。
第一个操作是灰度图像。
第二个是scaleFactor。由于很多人脸可能离摄像头很近,所以它们会比靠后的人脸看着要大很多。这一步中的比例因子(scale factor)就是为了缓解这个问题。
检测算法使用一个移动的窗口检测物体。minNeighbors 会定义在它声明检测到人脸前,在当前物体附近还要检测多少个物体。minSize 会定义每个窗口的大小。
注意,在这里的代码中,用的都是一些常见的值。在你实际操作中,可以试试不同的窗口大小、比例因子等等,直到发现最理想的参数值。
函数会返回一列边框,表示它发现了一个人脸。接着我们会循环函数认为检测到物体的地方。
print "Found{0}
faces!".format(len(faces))
# 画出围绕人脸的边框
for (x, y, w, h) in faces:
cv2.rectangle(image,
(x, y), (x+w, y+h), (0, 255, 0), 2)
该函数返回了 4 个值:边框的 x 和 y 位置,以及边框的宽和高(w,h)。
我们利用内置的 retangle() 函数用这些值画出一个边框。
cv2.imshow("Faces
found", image)
cv2.waitKey(0)
检查结果
咱们用代码库里的这张 ABBA 乐队的照片测试一下:
$ python face_detect.py
abba.png haarcascade_frontalface_default.xml
看样子程序能识别出人脸。再换一张照片试试:
呃···那个地方不是人脸···好吧咱们再试试。调整一下参数,发现将 scaleFactor 设为 1.2 后,就能把错误识别出的人脸给修正了。
刚才发生了什么?
第一张图拍摄距离比较近,照片质量也较高,而第二张图拍摄距离较远,很可能是用手机拍的。这就是为何需要调整 scaleFactor 的值。因此,必须根据自己的实际情况,设置算法的参数,避免出现假阳性。
提醒一下,虽然用我们的这种方法能很容易的识别人脸,但正确率不会达到 100%。不过在大部分情况下,你仍能得到足够理想的结果。
好了,现在可以自己去试试。
最终完整代码见这里:
https://github.com/shantnu/FaceDetect/blob/master/face_detect.pygithub.com