人脸检测方法有许多, 比如 opencv 自带的人脸 Haar 特征分类器和 dlib 人脸检测方法等.
对于 opencv 的人脸检测方法, 优点是简单, 快速; 存在的问题是人脸检测效果不好. 正面 / 垂直 / 光线较好的人脸, 该方法可以检测出来, 而侧面 / 歪斜 / 光线不好的人脸, 无法检测. 因此, 该方法不适合现场应用. 而对于 dlib 人脸检测方法采用 64 个特征点检测, 效果会好于 opencv 的方法识别率会更高, 本文会分别采用这几种方法来实现人脸识别. 那个算法更好, 跑跑代码就知道.
实时图像捕获
首先在进行人脸识别之前需要先来学点 OpenCV 的基础, 起码知道如何从摄像头获取当前拍到的图像吧. OpenCV 其实很简单, 接下来的代码就是最基本的起步点.
第一步: 打开本机上的摄像头, 实例化 VideoCapture 类
camera = cv2.VideoCapture(0)
开始第一帧图像的捕获, 这个方法用来测试当前的摄像头是否可用
success, frame = camera.read()
当 success 返回真时表示开始捕捉图像, 反则表示摄像头打开失败, 接下来就用最少的代码来打开摄像头并将当前的图像直接显示到一个窗口上, 具体代码结构如下:
- # coding=utf-8
- # ~/learn_face/cv_base.py
- from __future__ import print_function
- import cv2
- cameraCapture = cv2.VideoCapture(0)
- success, frame = cameraCapture.read()
- while success and cv2.waitKey(1) == -1:
- success, frame = cameraCapture.read()
- #TODO: 在此处可放置各种对当前每一帧图像的处理
- cv2.imshow("Camera", frame)
- cameraCapture.release()
- cv2.destroyAllWindows()
将上述代码存为 opencv_base.py 然后在命令行直接运行查看效果:
python opencv_base.py
效果如下:
HAAR 分类器
基于 Haar 特征的 cascade 分类器 (classifiers) 是 Paul Viola 和 Michael Jone 在 2001 年, 论文 "Rapid Object Detection using a Boosted Cascade of Simple Features" 中提出的一种有效的物品检测(object detect) 方法. 它是一种机器学习方法, 通过许多正负样例中训练得到 cascade 方程, 然后将其应用于其他图片.
在 OpenCV3 的源码的 data 目录中就可以找到已训练好的 HAAR 算法模型, 至 HAAR 算法的各种细节与理论有兴趣的直接去 Google 或者百度吧, 一搜一大堆. 花时间看一堆理论不如直接上代码, 由代码直接理解这些复杂理论的应用更适合开发人员, 毕竟我们不是数学家.
使用 HAAR 模型识别图像中的人脸其实只要三步走, 即使你对深度网络一点不懂也没关系, 再复杂的理论到最终不过是一个方法调用罢了, 了解清楚其中的原理就好.
第一步: 初始化分类器并载入已训练好的 HARR 模型:
face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml')
第二步: 通过 cv2.cvtColor 方法将当前的图像进行灰度化处理, 简化图像的信息:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
第三步: 然后将灰度化后的图像输入到分类器进行预判:
faces = face_cascade.detectMultiScale(gray, 1.3, 5) #识别人脸
只要 faces 数组的长度大于一就表示检测到当前画面中检测到人脸, 反之亦然. 简单来说其实人脸检测已经完成,
最后, 为了我们可以知道识别出来的结果, 我们可以将脸用方框给圈出来, 这里写个方法来圈脸:
- def mark_face(img,x,y,w,h):
- return cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
以下为本例的全部代码:
- # coding=utf-8
- # ~/learn_face/cv_haar.py
- from __future__ import print_function
- import cv2
- def mark_face(img, x, y, w, h):
- return cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
- cameraCapture = cv2.VideoCapture(0)
- success, frame = cameraCapture.read()
- face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml') # 1. 载入模型
- while success and cv2.waitKey(1) == -1:
- success, frame = cameraCapture.read()
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 2. 生成灰度图
- faces = face_cascade.detectMultiScale(
- gray,
- scaleFactor=1.1,
- minNeighbors=5
- ) # 3. 进行识别
- [mark_face(frame, *args) for args in faces] #画出识别的结果
- cv2.imshow("Camera", frame)
- cameraCapture.release()
- cv2.destroyAllWindows()
以下是运行效果:
运行起来就会觉得 HAAR 的识别效果不怎么样, 稍微动一下就很会识别不了.
Dlib
接下来我们试试用 DLib http://dlib.net/ 这个老牌的专做人脸识别起家的 C++ 库来试试, Dlib 是一个跨平台的 C++ 公共库, 除了线程支持, 网络支持, 提供测试以及大量工具等等优点, Dlib 还是一个强大的机器学习的 C++ 库, 包含了许多机器学习常用的算法. 同时支持大量的数值算法如矩阵, 大整数, 随机数运算等等. Dlib 同时还包含了大量的图形模型算法. 最重要的是 Dlib 的文档和例子都非常详细.
与 HAAR 分类器的检测方法相比 dLib 就简单得多了, 只需要用 dlib 自带的人脸检测器 detector 就够了, 连模型都省了! 之前的代码两步就能完成
第一步: 实例化 detector:
detector = dlib.get_frontal_face_detector()
第二步: 进行人脸检测
faces = detector(frame, 1)
That's all! 是不是很简单?
以下是本例的全部代码:
- # coding=utf-8
- # ~/learn_face/cv_dlib.py
- from __future__ import print_function
- import cv2
- import dlib
- cameraCapture = cv2.VideoCapture(0)
- success, frame = cameraCapture.read()
- detector = dlib.get_frontal_face_detector()
- while success and cv2.waitKey(1) == -1:
- success, frame = cameraCapture.read()
- faces = detector(frame, 1)
- for k, d in enumerate(faces):
- frame = cv2.rectangle(frame, (d.left(), d.top()),
- (d.right(), d.bottom()), (255, 0, 0), 2)
- cv2.imshow("Camera", frame)
- cameraCapture.release()
- cv2.destroyAllWindows()
运行上述代码后会发现 dlib 的效果真的比 HAAR 的检测效果要好很多! 不管头怎么转都能瞬间识别到, 画出来的矩形框都不带闪的!
特征点检测
接下来我们用 DLib 的特征点提取器 detector 所识别出来的人脸轮廓点给标记出来. 关键点 (landmarks) 提取需要一个特征提取器 predictor, 为了构建特征提取器, 预训练模型必不可少. 除了自行进行训练外, 可以使用官方提供的一个模型. 该模型可从 dlib sourceforge 库下载, 此模型是从人脸中提出 64 个特征点进行检测, 其准确度相当高.
具体实现思路如下:
第一步: 生成灰度图
第二步: 生成直方图
第三步: 进行检测
以下为全部代码
- # coding=utf-8
- # ~/learn_face/landmark.py
- import cv2
- import dlib
- cameraCapture = cv2.VideoCapture(0)
- success, frame = cameraCapture.read()
- detector = dlib.get_frontal_face_detector()
- predictor = dlib.shape_predictor(
- "shape_predictor_68_face_landmarks.dat")
- while success and cv2.waitKey(1) == -1:
- success, frame = cameraCapture.read()
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #生成灰度图
- clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) #生成直方图
- clahe_image = clahe.apply(gray)
- detections = detector(clahe_image, 1)
- for k, d in enumerate(detections):
- shape = predictor(clahe_image, d) # 获取坐标
- for i in range(1, 68): # 每张脸都有 68 个识别点
- cv2.circle(frame, (shape.part(i).x, shape.part(i).y), 1, (0, 0, 255),
- thickness=2)
- cv2.imshow("Camera", frame)
- cameraCapture.release()
- cv2.destroyAllWindows()
运行效果:
小结
我在 MacBook Pro 上跑以上的代码在速度是上没有什么很大区别的, 至少不会产生卡顿. 但如果换将代码植到树莓 3 和树莓 Zero 上区别就明显了, HAAR 分类器在树梅 Zero 上的运行时间平均在 1.2s 左右, 而 dlib 则需要 8s. 至于准确率 Dlib 又明显会优于 HAAR.
参考阅读
HAAR 分类器 https://zhuanlan.zhihu.com/p/31427728 - 这篇知乎上的文章对 HAAR 分类器的原理分析得很详尽, 有兴趣可以读一读
本文代码可到我的码云 https://gitee.com/ray_liang/learn_face 上下载
来源: https://www.cnblogs.com/Ray-liang/p/9900473.html