一、人脸检测实战
1.使用OpenCV进行人脸检测
OpenCV进行人脸检测使用的是名为 Viola-Jones 的目标检测框架的算法。
第一步:下载OpenCV库
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
第二步:找到默认的预训练权重文件
1.一般在python安装目录的上级目录的/lib/python3.7/site-packages/cv2/data目录下,有个haarcascade_frontalface_default.xml文件
2.例如:我的python安装路径为/Users/username/opt/anaconda3/envs/tensorflow/bin/python,
那么文件路径就为/Users/username/opt/anaconda3/envs/tensorflow/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml
3.将该文件拷贝到某一文件夹下
第三步:在拷贝的haarcascade_frontalface_default.xml文件的同级目录下,新建face_detect_cv3.py文件:
# -*- coding: utf-8 -*-
import cv2
import sys
# 获取相应参数
imagePath = sys.argv[1] #从命令行读取图片路径
cascPath = "haarcascade_frontalface_default.xml" #预训练的权重文件,这里使用相对路径
# 创建haar级联分类器
faceCascade = cv2.CascadeClassifier(cascPath)
# 读取图片并将BGR图像变换为灰度图
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 检测人脸图像
# scaleFactor:确定每个图像缩放比例大小。
# minNeighbors:确定每个候选矩形应保留多少个相邻框。
# minSize:最小目标的大小。小于该值的目标将被忽略。
# maxSize:最大目标的大小。大于该值的目标将被忽略。
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30)
#如果使用OpenCV3,则需要注释下面这句
#flags = cv2.CV_HAAR_SCALE_IMAGE
)
# x,y,w,h分别是人脸框区域的左上角点的坐标和人脸框的宽高
for (x, y, w, h) in faces:
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.imshow("Found {0} faces!".format(len(faces)), image)
cv2.waitKey(0)
第四步:在终端中运行
1. cd 到face_detect_cv3.py文件所在目录
2. python face_detect_cv3.py test.jpg #test.jpg是测试图像的路径,这里使用相对路径,所以要放在同级目录下
2.使用face_recognition库进行人脸检测
face_recognition使用dlib中最先进的人脸识别深度学习算法,其识别准确率在LFW数据集测试基准下达到了99.38%。
第一步:下载face_recognition库
pip install face_recognition -i https://pypi.tuna.tsinghua.edu.cn/simple
第二步:在测试图片test.jpg文件的同级目录下,新建face_detect_fr.py文件:
# -*- coding: utf-8 -*-
import cv2
import sys
import face_recognition
# 获取图片路径
imagePath = sys.argv[1]
# face_recognition加载图片
image = face_recognition.load_image_file(imagePath)
# 人脸检测
face_locations = face_recognition.face_locations(image)
# openCV读取图片
image = cv2.imread(imagePath)
# top,right,bottom,left分别是人脸框中最顶部,最右侧,最底部,最左侧的值
for (top, right, bottom, left) in face_locations:
cv2.rectangle(image, (left, top), (right, bottom), (0, 255, 0), 2)
cv2.imshow("Found {0} faces!".format(len(face_locations)), image)
cv2.waitKey(0)
第四步:在终端中运行
1. cd 到face_detect_cv3.py文件所在目录
2. python face_detect_cv3.py test.jpg #test.jpg是测试图像的路径,这里使用相对路径,所以要放在同级目录下
二、FaceNet简析
1.网络整体结构
对于一批人脸数据(此处的人脸数据就是通过人脸检测算法例如MTCNN检测出来的人脸数据,在我们的例子是96*96的图像),经过一个深度神经网络进行特征提取,然后经过L2正则将每个人脸数据映射为一个128维向量(这也就是embedding的结果)。然后将这些个128维的向量作为输入,计算triplet loss,将triplet loss作为损失函数来进行训练。然后将这些128维向量之间的欧式距离作为分类依据,距离小于某一个阈值,即视为同一个人。
2.三元组损失函数
- Triplet 三元组指的是:anchor, negative, positive 三个部分,每一部分都是一个 embedding 向量。
- anchor指的是基准图片,positive指的是与anchor同一分类下与anchor欧式距离最大的一张图片,negative指的是与anchor不同分类下与anchor欧式距离最小的一张图片。
- Triplet Loss可以让同一个人的不同人脸对应的embedding向量的欧式距离小,不同人脸对应的向量欧式距离大。
3.映射的特征空间维数
对于不同的特征维度D,特征越多并非越好。通过取不同的维数发现,embedding向量的维数为128更为合适。
4.分类
最后一步,相当于依据欧式距离做聚类了(个人觉得是一个有监督的聚类),可以使用SVM和KNN等聚类算法。
三、FaceNet使用预训练好的模型进行人脸检测
1.训练流程介绍
- 加载训练数据集
- 人脸检测、对齐和提取(使用 OpenFace 的人脸对齐工具 AlignDlib)
- 人脸特征向量学习(使用预训练的 nn4.small1.v1 模型)
- 人脸分类(使用 KNN 或 SVM)
- 实际上,我们是使用预训练好的模型进行人脸检测。所以只需要1,2,4步,第三步实际上是加载模型,所以在代码中不需要用到三元组损失函数来训练模型。
2.训练数据的形式
- 每人一个文件目录,目录以人名命名,如”Fan_Bingbing“
- 每个人的文件目录下包含10张图像(最好是1:1比例),图像文件以"人名_序号"命名,仅支持.jpg和.jpeg 两种格式。如”Fan_Bingbing_0001.jpg“。
- images目录下是亚洲人的人脸图片,origin_images目录下是欧美人的人脸图片
3.开始进行人脸检测
需要安装的库有keras、matplotlib、numpy、opencv、pydot、graphviz、sklearn
因为这一部分代码较多,所以把对代码的理解和部分函数的注释直接写在注释里了。
详情请看github中的face_recognition.ipynb文件。
4.模型测试与可视化分析
由于nn4.small2.v1模型是在欧美人的人脸数据集上训练的,因此识别欧美人比识别亚洲人更好。这一点,我们可以从以下几个方面查看:
- 准确率和F1值
在欧美人数据集上,不同的距离阈值对应的准确率和F1值的曲线如下图:
在亚洲人数据集上,不同的距离阈值对应的准确率和F1值的曲线如下图:
可以看到,在欧美人数据集上,当阈值为0.58时准确率最高为0.957;在亚洲人数据集上,当阈值为0.32时准确率最高为0.900。
- 特征向量之间的欧式距离直方图
在欧美人数据集上,同一个人和不同的人图片所对应的特征向量之间的欧式距离直方图如下,虚线表示最佳距离阈值:
在亚洲人数据集上,同一个人和不同的人图片所对应的特征向量之间的欧式距离直方图如下,虚线表示最佳距离阈值:
可以看到,在欧美人数据集上,同一个人的图像对应的特征向量在虚线左侧(即被预测为同一个人)的比例和不同的人的图像对应的特征向量在虚线右侧(即被预测为不同的人)的比例均高于在亚洲人数据集上的比例。
- 人脸特征向量降维之后的分布
在欧美人数据集上,将每个人的照片对应的128维特征向量降维之后展现在二维平面如下:
在亚洲人数据集上,将每个人的照片对应的128维特征向量降维之后展现在二维平面如下:
可以看到欧美人对应的降维后的结果,聚类更加明显,类别之间的区分度更大。