0. 引言
利用 Python 开发,借助 Dlib 库捕获摄像头中的人脸,进行实时人脸 68 个特征点标定;
支持多张人脸;
有截图功能;
图 1 工程效果示例( gif )
图 2 工程效果示例( 静态图片 )
1.开发环境
Python: 3.6.3
Dlib: 19.7
OpenCv, NumPy
import dlib #人脸检测的库 Dlib
import numpy as np #数据处理的库 NumPy
import cv2 #图像处理的库 OpenCv
2. 源码介绍
其实实现很简单,主要分为两个部分:摄像头调用 + 人脸特征点标定
2.1 摄像头调用
介绍下 OpenCv 中摄像头的调用方法,用到以下几个 OpenCv 函数:
cv2.VideoCapture(0) 创建一个对象;
cv2.VideoCapture.set(propId, value) 设置视频参数;
cv2.VideoCapture.isOpened() 检测读取视频是否成功;
cv2.VideoCapture.read() 返回是否读取成功和读取到的帧图像;
关于 cv2 中 VideoCapture 类的一些函数参数的说明如下:
#Sort by coneypo#Updated at 10, Oct#Blog:
###### 1. cv2.VideoCapture(), 创建cv2摄像头对象 / Open the default camera ######
"""Python: cv2.VideoCapture() →
Python: cv2.VideoCapture(filename) →
filename – name of the opened video file (eg. video.avi) or image sequence (eg. img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...)
Python: cv2.VideoCapture(device) →
device – id of the opened video capturing device (i.e. a camera index). If there is a single camera connected, just pass 0."""cap=cv2.VideoCapture(0)##### 2. cv2.VideoCapture.set(propId, value),设置视频参数; #####
"""propId:
CV_CAP_PROP_POS_MSEC Current position of the video file in milliseconds.
CV_CAP_PROP_POS_FRAMES 0-based index of the frame to be decoded/captured next.
CV_CAP_PROP_POS_AVI_RATIO Relative position of the video file: 0 - start of the film, 1 - end of the film.
CV_CAP_PROP_FRAME_WIDTH Width of the frames in the video stream.
CV_CAP_PROP_FRAME_HEIGHT Height of the frames in the video stream.
CV_CAP_PROP_FPS Frame rate.
...
value: 设置的参数值/ Value of the property"""cap.set(3, 480)##### 3. cv2.VideoCapture.isOpened(), 检查摄像头初始化是否成功, 返回true或false / check if open camera successfully #####
cap.isOpened()##### 4. cv2.VideoCapture.read([imgage]) -> retval,image, 读取视频 / Grabs, decodes and returns the next video frame #####
"""返回两个值:
一个是布尔值true/false,用来判断读取视频是否成功/是否到视频末尾
图像对象,图像的三维矩阵"""flag, im_rd= cap.read()
2.2 人脸特征点标定
调用预测器 “shape_predictor_68_face_landmarks.dat” 进行 68 点标定,这是 Dlib 训练好的模型,可以直接调用,进行人脸 68 个人脸特征点的标定;
需要进行的后续工作是,利用坐标值进行特征点绘制;
图 3 Dlib 中人脸 68 个特征点位置说明
2.3 源码
既然已经能够利用训练好的模型进行特征点检测,需要进行的工作是将摄像头捕获到的视频流,转换为 OpenCv 的图像对象,这样才能进行人脸特征点检测;
然后利用返回的特征点坐标值,绘制特征点,实时的再绘制到摄像头界面上,达到实时人脸检测追踪的目的;
利用 cv2.VideoCapture() 创建摄像头对象,然后利用 flag, im_rd = cv2.VideoCapture.read() 读取摄像头视频,im_rd 就是视频中的一帧帧图像;
然后就类似于单张图像进行人脸检测,对这一帧帧的图像 im_rd 利用 Dlib 进行特征点标定,然后绘制特征点;
可以按下 's' 键来获取当前截图,会存下带有时间戳的本地图像文件如 “screenshoot_1_2018-05-14-11-04-23.jpg”;
或者按下 'q' 键来退出摄像头窗口;
有四个 python 文件:
how_to_use_camera.py OpenCv 调用摄像头;
get_features_from_image.py 绘制 "data/face_to_detect/face_x.jpg" 本地图像人脸文件的特征点;
get_features_from_camera.py 从摄像头实时人脸检测绘制特征点;
remove_ss.py: 删除 "data/screenshots/" 路径下的所有截图;
这里只给出 get_features_from_camera.py 的源码;
get_features_from_camera.py:
1 #调用摄像头,进行人脸捕获,和 68 个特征点的追踪
2
3 #Author: coneypo
4 #Blog:
5 #GitHub: https://github.com/coneypo/Dlib_face_detection_from_camera
6
7 #Created at 2018-02-26
8 #Updated at 2019-01-28
9
10 import dlib #机器学习的库 Dlib
11 import numpy as np #数据处理的库 numpy
12 import cv2 #图像处理的库 OpenCv
13 importtime14 importtimeit15 importstatistics16
17 #储存截图的目录
18 path_screenshots = "data/screenshots/"
19
20 detector =dlib.get_frontal_face_detector()21 predictor = dlib.shape_predictor('data/dlib/shape_predictor_68_face_landmarks.dat')22
23 #创建 cv2 摄像头对象
24 cap =cv2.VideoCapture(0)25
26 #cap.set(propId, value)
27 #设置视频参数,propId 设置的视频参数,value 设置的参数值
28 cap.set(3, 480)29
30 #截图 screenshots 的计数器
31 cnt =032
33 time_cost_list =[]34
35 #cap.isOpened() 返回 true/false 检查初始化是否成功
36 whilecap.isOpened():37
38 #cap.read()
39 #返回两个值:
40 #一个布尔值 true/false,用来判断读取视频是否成功/是否到视频末尾
41 #图像对象,图像的三维矩阵
42 flag, im_rd =cap.read()43
44 #每帧数据延时 1ms,延时为 0 读取的是静态帧
45 k = cv2.waitKey(1)46
47 #取灰度
48 img_gray =cv2.cvtColor(im_rd, cv2.COLOR_RGB2GRAY)49
50 #start point
51 start =timeit.default_timer()52
53 #人脸数
54 faces =detector(img_gray, 0)55
56 #print(len(faces))
57
58 #待会要写的字体
59 font =cv2.FONT_HERSHEY_SIMPLEX60
61 #标 68 个点
62 if len(faces) !=0:63 #检测到人脸
64 for i inrange(len(faces)):65 landmarks = np.matrix([[p.x, p.y] for p inpredictor(im_rd, faces[i]).parts()])66
67 for idx, point inenumerate(landmarks):68 #68 点的坐标
69 pos = (point[0, 0], point[0, 1])70
71 #利用 cv2.circle 给每个特征点画一个圈,共 68 个
72 cv2.circle(im_rd, pos, 2, color=(139, 0, 0))73
74 #利用 cv2.putText 输出 1-68
75 cv2.putText(im_rd, str(idx + 1), pos, font, 0.2, (187, 255, 255), 1, cv2.LINE_AA)76
77 cv2.putText(im_rd, "faces:" + str(len(faces)), (20, 50), font, 1, (0, 0, 0), 1, cv2.LINE_AA)78
79 #end point
80 stop =timeit.default_timer()81 time_cost_list.append(stop -start)82 print("%-15s %f" % ("Time cost:", (stop -start)))83
84 else:85 #没有检测到人脸
86 cv2.putText(im_rd, "no face", (20, 50), font, 1, (0, 0, 0), 1, cv2.LINE_AA)87
88
89 #添加说明
90 im_rd = cv2.putText(im_rd, "press 'S': screenshot", (20, 400), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)91 im_rd = cv2.putText(im_rd, "press 'Q': quit", (20, 450), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)92
93 #按下 's' 键保存
94 if k == ord('s'):95 cnt += 1
96 print(path_screenshots + "screenshot" + "_" + str(cnt) + "_" + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + ".jpg")97 cv2.imwrite(path_screenshots + "screenshot" + "_" + str(cnt) + "_" + time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + ".jpg", im_rd)98
99 #按下 'q' 键退出
100 if k == ord('q'):101 break
102
103 #窗口显示
104 #参数取 0 可以拖动缩放窗口,为 1 不可以
105 #cv2.namedWindow("camera", 0)
106 cv2.namedWindow("camera", 1)107
108 cv2.imshow("camera", im_rd)109
110 #释放摄像头
111 cap.release()112
113 #删除建立的窗口
114 cv2.destroyAllWindows()115
116 print("%-15s" % "Result:")117 print("%-15s %f" % ("Max time:", (max(time_cost_list))))118 print("%-15s %f" % ("Min time:", (min(time_cost_list))))119 print("%-15s %f" % ("Average time:", statistics.mean(time_cost_list)))
实时输出处理时间:
...
Time cost: 0.065273Time cost:0.059348Time cost:0.093570Time cost:0.091448Time cost:0.084946Time cost:0.089457Time cost:0.084367Time cost:0.094103Time cost:0.096082Time cost:0.073331Time cost:0.073685Time cost:0.065583Time cost:0.061161Time cost:0.061650Time cost:0.060952Time cost:0.084485Result:
Max time:0.112430Min time:0.057525Average time:0.085478
笔记本 CPU: i5-6200U@2.30GHz, Memory: 8G 处理时间平均在 0.08s;