原先我们的门禁系统在录入人脸照片时,会调用阿里云视觉智能开放平台进行人脸检测与五官定位,初步的判定照片的质量。现在项目里有内网私有化部署的需求,云厂的接口不再可行,需要寻找一种本地人脸检测的方案。
此系列博客的目的重点在于替代检测而非识别。关注识别的,可以暂时绕开,等待博主有场景需求时再更新。本文的示例基于 dlib 框架,不要问为什么,因为这个上手更简单。有限的时间里,先拿软柿子捏。
引言
人脸检测是计算机视觉最典型的应用之一,早期 OpenCV 的 logo 就是 Haar 人脸检测的示意图。很多人的第一个 OpenCV 学习目标就是跑通 Haar 级联人脸检测,dlib 库在业内开始流行很大程度上是因为其 HOG-SVM 人脸检测比 OpenCV Haar 的好,而近年来 OpenCV 和 dlib 均已包含基于深度学习的人脸检测算法实现。
现行阿里云方案
要想替代,先得了解他能做什么。我们目前采用的是阿里云视觉智能开放平台>人脸人体>人脸检测>人脸检测与五官定位的功能。
功能描述
人脸检测与五官定位能力可以检测图片中的人脸并给出每张人脸定位和关键点信息。输出人脸数量、人脸矩形坐标、人脸姿态、双瞳孔中心坐标、人脸置信度列表等信息。支持检测含有多张人脸的照片。
应用场景
人脸关键点检测,是后续识别、分析和特效应用的基础。它为人脸识别、表情分析、疲劳检测、三维人脸重建、人脸美颜、换脸等人脸相关应用提供了人脸精确信息。
特色优势
稠密关键点:提供105个关键点,足以应对人脸识别、姿态矫正、换脸等要求高精度人脸定位的应用。
适应能力强:适应最大 90 度侧脸,平面 360 旋转人脸等情景。适用于各种应用场景。
支持多人脸:支持在同张图中检测上千个人脸。
输入限制
图像格式:JPEG、JPG、PNG、BMP。
图像大小:不超过 3 MB。
图像分辨率:大于 32×32 像素,小于 4096×4096 像素,人脸占比不低于 64×64 像素。
URL 地址中不能包含中文字符。
示例
{
"RequestId" : "E567D988-8072-43CF-B835-7AEF09FC5C1C",
"Data" : {
"FaceProbabilityList" : 0.929632306098938,
"LandmarkCount" : 105,
"FaceRectangles" : [ 144, 18, 326, 405 ],
"Landmarks" : [ 177.1269073486328, 141.56689453125, 271.990478515625, 137.91294860839844, 223.6563262939453, 123.32662200927734, 224.28944396972656, 137.8303985595703, 190.42523193359375, 133.11012268066406, 206.60804748535156, 125.30608367919922, 240.8021240234375, 125.39529418945312, 257.24346923828125, 128.51979064941406, 191.29269409179688, 141.09840393066406, 207.5005645751953, 138.24703979492188, 240.81582641601562, 140.5307159423828, 257.2742004394531, 143.53077697753906, 343.474609375, 135.4432373046875, 441.0479736328125, 136.6552276611328 ],
"Qualities" : {
"NoiseList" : 96.94622039794922,
"ScoreList" : 98.24667358398438,
"BlurList" : 99.35592651367188,
"MaskList" : 99.75968170166016,
"GlassList" : 99.99040222167969,
"FnfList" : 100,
"PoseList" : 99.88871002197266,
"IlluList" : 99.84143829345703
},
"FaceCount" : 1,
"PoseList" : [ 0.2377411127090454, 1.8424458503723145, 0.3763512670993805 ],
"Pupils" : [ 232.3559112548828, 173.39218139648438, 18.214069366455078, 387.1202392578125, 174.74411010742188, 18.214069366455078 ]
}
}
FaceProbabilityList
截图中包含人脸的概率,取值范围 0~1。如有多个人脸,则依次返回。例如有两个人脸则返回[face_prob1, face_prob2]。图像中人脸区域分辨率越大,人脸越清晰,人脸正视,对应的该值越大。LandmarkCount
人脸特征点数目,目前固定为 105 点。依次为:眉毛 24 点,眼睛 32 点,鼻子 6 点,嘴巴 34 点,外轮廓 9 点。FaceRectangles
返回人脸矩形框,分别是[left, top, width, height]。如有多个人脸,则依次顺延,返回矩形框。例如有两个人脸则返回[left1, top1, width1, height1, left2, top2, width2, height2]。Landmarks
人脸特征点定位结果,每个人脸返回一组特征点位置,表示方式为(x0, y0, x1, y1, ……);如有多个人脸,则依次顺延,返回定位浮点数。Qualities
人脸质量情况,分数越高表示越有利于识别。其中 ScoreList 为质量综合分数,BlurList 为人脸模糊度对识别的影响分数,FnfList 为人脸正确度对识别的影响分数,GlassList 为眼镜等上半脸遮挡对识别的影响分数,IlluList 为光照对识别的影响分数,MaskList 为口罩等下半脸遮挡对识别的影响分数,NoiseList 为图片噪声对识别的影响分数,PoseList 为姿态对识别的影响分数。FaceCount
检测出的人脸个数。PoseList
返回人脸姿态,格式为[yaw, pitch, roll]。如有多个人脸,则依次顺延。
yaw 为左右角度,取值范围-90~90。
pitch 为上下角度,取值范围-90~90。
roll 为平面旋转角度,取值范围-180~180。Pupils
左右两个瞳孔的中心点坐标和半径,每个人脸 6 个浮点数,顺序为[left_iris_cenpt.x, left_iris_cenpt.y, left_iris_radius, right_iris_cenpt.x, right_iris_cenpt.y, right_iris_radis]。
基于 dlib 的方案
dlib 介绍
dlib 是较流行的人脸识别的开源库,使用 c++编写,里面包含了许多的机器学习算法,在 python 中也可以使用。dlib 保持着很好的更新节奏,文档也写得相当清晰,涉及到的资源都有标明在哪里下载,是一个优秀的人脸识别开源库。dlib 库采用 68 点位置标志人脸重要部位,比如 18-22 点标志右眉毛,51-68 标志嘴巴。
face_recognition 介绍
face_recognition是一个强大、简单、易上手的人脸识别开源项目,并且配备了完整的开发文档和应用案例,特别是兼容树莓派系统。基于业内领先的 C++开源库 dlib 中的深度学习模型,用 Labeled Faces in the Wild 人脸数据集进行测试,有高达 99.38%的准确率。但对小孩和亚洲人脸的识别准确率尚待提升。此次基于 python 的人脸学习就是基于这个项目。
先把 DEMO 跑起来
基于 docker 镜像能大幅提升运行环境的搭建。假设大家都会点 docker 的基础技能,也安装好了 docker 环境。执行以下一个命令即可。
docker run -i -t -v ~/mydata/face:/mydata/face animcogn/face_recognition:latest /bin/bash
我是将自己的磁盘的/mydata/face/挂在到了容器的/mydata/face/目录,这样上传下载素材更方便。
识别人脸关键点
准备涨照片,命名为1.jpg
,扔到/mydata/face/目录下;在把landmarks.py
也扔进去,内容如下。准备工作就完成了。
from PIL import Image
import face_recognition
# Load the jpg file into a numpy array
image = face_recognition.load_image_file("1.jpg")
# Find all the faces in the image using the default HOG-based model.
# This method is fairly accurate, but not as accurate as the CNN model and not GPU accelerated.
# See also: find_faces_in_picture_cnn.py
face_locations = face_recognition.face_locations(image)
print("图片中检测到人脸:{} 张。".format(len(face_locations)))
for face_location in face_locations:
# Print the location of each face in this image
top, right, bottom, left = face_location
print("人脸在图片中的坐标位置(px) 上: {}, 左: {}, 下: {}, 右: {}".format(top, left, bottom, right))
# You can access the actual face itself like this:
face_image = image[top:bottom, left:right]
pil_image = Image.fromarray(face_image)
pil_image.show()
face_landmarks_list = face_recognition.face_landmarks(image)
for face_landmarks in face_landmarks_list:
# Print the location of each facial feature in this image
for facial_feature in face_landmarks.keys():
print("人脸的 {} 检测到关键特征点: {}".format(facial_feature, face_landmarks[facial_feature]))
pil_image.show()
在/mydata/face/目录下执行: python3 find_faces_in_picture.py
我的结果如下:
图片中检测到人脸:1 张。
人脸在图片中的坐标位置(px) 上: 320, 左: 468, 下: 587, 右: 735
人脸的 chin 检测到关键特征点: [(429, 356), (422, 399), (418, 445), (421, 486), (440, 526), (467, 559), (498, 586), (534, 607), (570, 614), (599, 607), (618, 582), (636, 556), (651, 527), (665, 495), (675, 463), (683, 430), (686, 400)]
人脸的 left_eyebrow 检测到关键特征点: [(497, 342), (527, 331), (558, 333), (585, 344), (609, 360)]
人脸的 right_eyebrow 检测到关键特征点: [(644, 365), (660, 360), (675, 357), (688, 359), (693, 370)]
人脸的 nose_bridge 检测到关键特征点: [(622, 381), (625, 404), (628, 428), (631, 452)]
人脸的 nose_tip 检测到关键特征点: [(585, 464), (597, 467), (609, 473), (620, 472), (630, 467)]
人脸的 left_eye 检测到关键特征点: [(530, 366), (547, 362), (563, 365), (572, 377), (559, 378), (543, 374)]
人脸的 right_eye 检测到关键特征点: [(636, 385), (648, 378), (660, 379), (666, 388), (659, 392), (648, 390)]
人脸的 top_lip 检测到关键特征点: [(541, 514), (564, 510), (585, 510), (598, 514), (609, 512), (616, 515), (620, 521), (615, 520), (607, 518), (595, 520), (583, 518), (548, 515)]
人脸的 bottom_lip 检测到关键特征点: [(620, 521), (610, 531), (602, 535), (590, 537), (576, 536), (558, 530), (541, 514), (548, 515), (581, 520), (594, 522), (606, 520), (615, 520)]
方案对比
我们在场景下的需求如下:
识别照片中有多少张人脸,我们的诉求是每张照片里仅有一张人脸。目前看阿里和 dlib 都能满足这个基础的要求。
人脸质量得分,能通过设置分值快速的过滤照片质量,比如高于 80 为合格照片。这个使用 dlib 得自己实现了。
人脸姿态判断,人脸在照片中的姿态是否比较正,允许倾斜 15 度。
判断越精准越好。
关键特征点
细心的杠精可能真对会去数一数,比如说我自己。。。
看运行的结果,嘴巴共有 24 个关键点,上嘴唇和下嘴唇各 12,而我的对比表里写的是 22 个。实际上嘴唇和下嘴唇有 2 个关键点是重复计算的,分别是 49 和 55。
从关键特征点数量上看,阿里云的人脸检测功能明显高于 Dlib,商业版和开源版还是有很大区别的。看在钱的面子上,我觉得 68 个点也不是不能接受。
人脸姿态
阿里云的人脸检测功能能够直接返回人脸姿态情况,包含:左右、上下、平面旋转角度。翻遍了 face_recognition 的所有功能都没有直接的 API。不过,有了 68 个点,也不是不能解决的。以下图为例:
通过识别两个眼睛的坐标点,可以计算出 a 和 b 的边长,并 a 和 b 的夹角为 90°。理论上就可以利用三角函数计算出照片中人脸的倾斜角度了。嗯…招个高中生吧……
参考资料
face_recognition github
face_recognition dockerhub
あずにゃん的博客:关键点提取:face_recognition、疲劳检测、人脸校准、人脸数据库