这里我们将要介绍如何使用python进行简单的人脸检测与人脸识别,并且通过gpu来加速。
注意:这里都是基础内容,如果需要更加强大深入的请出门左转。
下面介绍简单人脸检测与识别需要使用到的几个重要依赖。
我所使用的环境是windows 10 + python3.6(64位)
- numpy
- OpenCV
- Dlib
- face_recognition
- haarcascades
- shape_predictor
小基础
python安装依赖可以选择在线安装,如 pip install 依赖名
也可以选择使用whl文件安装,如 pip install whl文件位置
基于我的环境,我使用的是numpy‑1.15.2+mkl‑cp36‑cp36m‑win_amd64.whl
这个版本,大家可以根据自己环境选择适合自己的版本下载。
安装使用命令 pip3 install numpy‑1.15.2+mkl‑cp36‑cp36m‑win_amd64.whl
我使用的是opencv_python‑3.4.3‑cp36‑cp36m‑win_amd64.whl
这个版本。
安装使用命令 pip3 install opencv_python‑3.4.3‑cp36‑cp36m‑win_amd64.whl
我使用的是dlib-19.8.1-cp36-cp36m-win_amd64.whl
。
安装使用命令 pip3 install dlib-19.8.1-cp36-cp36m-win_amd64.whl
安装使用命令 pip3 install face_recognition
安装使用命令 pip3 install keras
前面部分用不到,后面高级应用会用到,可提前下载安装,也可后面需要的时候安装
安装使用命令: pip3 install tensorflow
前面部分用不到,后面高级应用会用到,可提前下载安装,也可后面需要的时候安装
基于目前的数据量和个人知识与能力,我还不能自己利用机器学习来训练数据模型,所以使用的是国外别人已经训练好的数据模型。
上面链接中所有的xml都推荐下载到本地备用,我所使用的是haarcascade_frontalface_default.xml
我所使用的是shape_predictor_68_face_landmarks.dat.bz2
和shape_predictor_5_face_landmarks.dat.bz2
这两个。
推荐大家把这两个都下载下来,并解压,我们所需要的是里面的dat
数据文件。
好了,有了上面的这些基础环境与依赖,我们可以继续我们接下来的简单人脸检测与识别了。
没有装好这些环境的同学请注意了,我们班级已经与谷歌、百度等大公司达成合作,有任何问题请在Google和Baidu进行搜索,他们会提供你所需要的答案。
在这一节不会讲解复杂的人脸识别,只是先通过简单的小例子让大家先了解一下人脸识别需要用到什么、人脸识别的基本步骤等等最简单的内容。
- 先将图片灰度化,为了降低图片颜色维度,减少后续识别计算量
- 然后利用OpenCV加载别人训练好的人脸分类器,通过这个分类器来检测人脸
- 在原图片上画一个矩形,然后显示出来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| import cv2
filepath = "img/sdu/6.jpg"
classifier = cv2.CascadeClassifier(
"lib/opencv/haarcascades/haarcascade_frontalface_default.xml"
)
img = cv2.imread(filepath) # 读取图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度化
color = (0, 255, 0) # 定义绘制颜色
# 调用识别人脸
faceRects = classifier.detectMultiScale(
gray, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))
if len(faceRects): # 大于0则检测到人脸
for faceRect in faceRects: # 单独框出每一张人脸
x, y, w, h = faceRect
# 框出人脸
cv2.rectangle(img, (x, y), (x + h, y + w), color, 2)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
在人脸检测方面实现方法与上面图片的实现方法一模一样,只是这个图片是从摄像头不断获取的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| import cv2
def scan(img):
grayImg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
classifier = cv2.CascadeClassifier(
"lib/opencv/haarcascades/haarcascade_frontalface_default.xml"
)
color = (0, 255, 0) # 定义绘制颜色
faceRects = classifier.detectMultiScale(
grayImg, scaleFactor=1.2, minNeighbors=3, minSize=(32, 32))
if len(faceRects): # 大于0则检测到人脸
for faceRect in faceRects: # 单独框出每一张人脸
x, y, w, h = faceRect
cv2.rectangle(img, (x, y), (x + h, y + w), color, 2)
cv2.imshow("image", img)
cap = cv2.VideoCapture(0)
while (1):
ret, frame = cap.read()
scan(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
|
Dlib里面有很多算法,可以实现一些复杂的人脸识别。
在这一小节只演示用dlib内部自带的默认的人脸识别模型来进行人脸检测
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| import cv2
import dlib
path = "img/sdu/658.jpg"
img = cv2.imread(path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#人脸分类器
detector = dlib.get_frontal_face_detector()
dets = detector(gray, 1)
for face in dets:
#在图片中标注人脸边框,并显示
left = face.left()
top = face.top()
right = face.right()
bottom = face.bottom()
cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 2)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
都是相同的步骤呀,与上面大同小异
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| import cv2
import dlib
detector = dlib.get_frontal_face_detector() #使用默认的人类识别器模型
def scan(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dets = detector(gray, 1)
for face in dets:
left = face.left()
top = face.top()
right = face.right()
bottom = face.bottom()
cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 2)
cv2.imshow("image", img)
cap = cv2.VideoCapture(0)
while (1):
ret, img = cap.read()
scan(img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
|
在两个视频中人脸检测中,我们发现
在识别准确率上 Dlib > OpenCV
但是在速度上 OpenCV > Dlib
后面我们会有专门的内容讲解通过GPU加速Dlib
上面已经介绍过了简单的从一张图片或视频中的每一帧中检测到人脸并进行画框
在这一小节,我们会进一步利用Dlib这个库中更加强大的工具来实现稍微发杂一些的人脸检测任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| import cv2
import dlib
path = "img/ag.png"
img = cv2.imread(path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#人脸分类器
detector = dlib.get_frontal_face_detector()
# 获取人脸检测器
predictor = dlib.shape_predictor(
"lib/dlib/shape_predictor_68_face_landmarks.dat"
#这里使用68点的模型,将68改成5就是使用5点的模型
)
dets = detector(gray, 1)
for face in dets:
shape = predictor(img, face) # 寻找人脸的68个标定点
# 遍历所有点,打印出其坐标,并圈出来.
for pt in shape.parts():
pt_pos = (pt.x, pt.y)
cv2.circle(img, pt_pos, 1, (0, 255, 0), 2)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
上人脸识别的主菜
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| import cv2
import face_recognition
import os
path = "img/face_5107"
cap = cv2.VideoCapture(0)
total_image_name = []
total_face_encoding = []
for fn in os.listdir(path): #fn 表示的是文件名q
print(path + "/" + fn)
total_face_encoding.append(
face_recognition.face_encodings(
face_recognition.load_image_file(path + "/" + fn))[0])
fn = fn[:(len(fn) - 4)] #截取图片名(这里应该把images文件中的图片名命名为为人物名)
total_image_name.append(fn) #图片名字列表
while (1):
ret, frame = cap.read()
# 发现在视频帧所有的脸和face_enqcodings
face_locations = face_recognition.face_locations(frame)
face_encodings = face_recognition.face_encodings(frame, face_locations)
# 在这个视频帧中循环遍历每个人脸
for (top, right, bottom, left), face_encoding in zip(
face_locations, face_encodings):
# 看看面部是否与已知人脸相匹配。
for i, v in enumerate(total_face_encoding):
match = face_recognition.compare_faces(
[v], face_encoding, tolerance=0.4)
name = "Unknown"
if match[0]:
name = total_image_name[i]
break
# 画出一个框,框住脸
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
# 画出一个带名字的标签,放在框下
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255),
cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0,
(255, 255, 255), 1)
# 显示结果图像
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| import face_recognition
from PIL import Image, ImageDraw
# 将图片文件加载到numpy 数组中
image = face_recognition.load_image_file("img/ag.png")
#查找图像中所有面部的所有面部特征
face_landmarks_list = face_recognition.face_landmarks(image)
for face_landmarks in face_landmarks_list:
facial_features = [
'chin', # 下巴
'left_eyebrow', # 左眉毛
'right_eyebrow', # 右眉毛
'nose_bridge', # 鼻樑
'nose_tip', # 鼻尖
'left_eye', # 左眼
'right_eye', # 右眼
'top_lip', # 上嘴唇
'bottom_lip' # 下嘴唇
]
pil_image = Image.fromarray(image)
d = ImageDraw.Draw(pil_image)
for facial_feature in facial_features:
d.line(face_landmarks[facial_feature], fill=(255, 255, 255), width=2)
pil_image.show()
|
使用keras实现性别识别
模型数据使用的是oarriaga/face_classification的模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| import cv2
from keras.models import load_model
import numpy as np
import chineseText
img = cv2.imread("img/xingye-1.png")
face_classifier = cv2.CascadeClassifier(
"lib/opencv/haarcascades/haarcascade_frontalface_default.xml"
)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_classifier.detectMultiScale(
gray, scaleFactor=1.2, minNeighbors=3, minSize=(140, 140))
gender_classifier = load_model(
"classifier/gender_models/simple_CNN.81-0.96.hdf5")
gender_labels = {0: '女', 1: '男'}
color = (255, 255, 255)
for (x, y, w, h) in faces:
face = img[(y - 60):(y + h + 60), (x - 30):(x + w + 30)]
face = cv2.resize(face, (48, 48))
face = np.expand_dims(face, 0)
face = face / 255.0
gender_label_arg = np.argmax(gender_classifier.predict(face))
gender = gender_labels[gender_label_arg]
cv2.rectangle(img, (x, y), (x + h, y + w), color, 2)
img = chineseText.cv2ImgAddText(img, gender, x + h, y, color, 30)
cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| import cv2
from keras.models import load_model
import numpy as np
import chineseText
import datetime
startTime = datetime.datetime.now()
emotion_classifier = load_model(
'classifier/emotion_models/simple_CNN.530-0.65.hdf5')
endTime = datetime.datetime.now()
print(endTime - startTime)
emotion_labels = {
0: '生气',
1: '厌恶',
2: '恐惧',
3: '开心',
4: '难过',
5: '惊喜',
6: '平静'
}
img = cv2.imread("img/emotion/emotion.png")
face_classifier = cv2.CascadeClassifier(
"C:\Python36\Lib\site-packages\opencv-master\data\haarcascades\haarcascade_frontalface_default.xml"
)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_classifier.detectMultiScale(
gray, scaleFactor=1.2, minNeighbors=3, minSize=(40, 40))
color = (255, 0, 0)
for (x, y, w, h) in faces:
gray_face = gray[(y):(y + h), (x):(x + w)]
gray_face = cv2.resize(gray_face, (48, 48))
gray_face = gray_face / 255.0
gray_face = np.expand_dims(gray_face, 0)
gray_face = np.expand_dims(gray_face, -1)
emotion_label_arg = np.argmax(emotion_classifier.predict(gray_face))
emotion = emotion_labels[emotion_label_arg]
cv2.rectangle(img, (x + 10, y + 10), (x + h - 10, y + w - 10),
(255, 255, 255), 2)
img = chineseText.cv2ImgAddText(img, emotion, x + h * 0.3, y, color, 20)
cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
|
在前面的小实验中我们发现了,使用Dlib来实现的人脸检测与识别速度很慢,在视频中很难实现实时性。
所以我们不仅要想,是否可以用GPU加速一下。
以前可能很麻烦,现在英伟达推出的CUDA就专门为了解决这个而生。
CUDA下载链接
下载并安装,不必多说,一路下一步
cudnn下载链接
这里下载需要注册英伟达账号,注册就行,下载下来后解压,里面提供cudnn库文件以及头文件,需要把cudnn目录下的bin、include以及lib目录中的文件拷贝到相应的cuda目录中的bin、include和lib目录中去。
cmake是要在后面编译Dlib用到的。
cmake下载链接
记住安装并添加path。
这里我们跳过,因为后面可以直接在安装Dlib库时让他自动编译,能自动搞何必去麻烦,如果感兴趣可以自己去编译。
我们打开64位的cmd(这一个会在安装VS2017的时候提供),或者打开64位的Powershell,在里面运行安装命令
python setup.py install --yes DLIB_USE_CUDA
这一个命令会自动编译Dlib并且安装,就不用操心了。
在cmake编译的过程中可能会报出各种问题,稍微总结一下:
如果出现类似于没找到相应编译器的原因,说明vs安装可能有问题,可能是vs版本比较老,vs安装不正确,或者vs安装不完整。不管怎么说vs的安装时间会需要很长时间,而且由于vs版本的问题,安装新的vs可能会出现各种问题,如果想手动卸载重装就更坑了,这个时候可以用卸载工具进行卸载:https://github.com/Microsoft/VisualStudioUninstaller/releases,下载之后直接解压然后以运行可执行程序,等待自动清理完成,然后重新安装vs;
如果出现类似于找不到cuda的问题,请确认是否正确安装cuda;并且,如果提示找到了cuda但没有正确的cudnn,请确认是否正确地把cudnn中的lib、include和bin目录中的文件拷贝到相应的cuda目录底下;
在使用cmake编译的时候如果你更改了配置,那么需要在cmake‘中点击file中的delete cache,然后重新configure;
有一种很奇葩的现象是,有可能你的机器上已经安装过了cuda和cudnn,并且之前使用cmake configure的时候成功编译完成得到dlib的python库,但是出于某些原因需要重新安装cuda和cudnn,那么不仅需要手动卸载之前的cuda,而且最好也删除site-packages目录中所有和dlib相关的目录和文件,以及cmake输出得到的临时文件,然后重新安装cuda和cudnn,并且按照之前的步骤执行python setup.py install –yes DLIB_USE_CUDA,得到dlib的python库文件。
如果编译顺利,并且中间没有报错,可以新建一个python程序,然后import dlib成功,大功告成。
python脚本运行
1
2
3
4
| import dlib
print(dlib.__)
print(dlib.DLIB_USE_CUDA)
print(dlib.cuda.get_num_devices())
|