一, 介绍
我想做的是基于人脸识别的表情 (情绪) 分析. 看到网上也是有很多的开源库提供使用, 为开发提供了很大的方便. 我选择目前用的比较多的 dlib 库进行人脸识别与特征标定. 使用 python 也缩短了开发周期.
官网对于 dlib 的介绍是: Dlib 包含广泛的机器学习算法. 所有的设计都是高度模块化的, 快速执行, 并且通过一个干净而现代的 C ++ API, 使用起来非常简单. 它用于各种应用, 包括机器人技术, 嵌入式设备, 手机和大型高性能计算环境.
虽然应用都比较高大上, 但是自己在 PC 上做个情绪分析的小软件还是挺有意思的.
按照自己的想法与思路设计识别方式. 目前也比较火的 keras 好像就是根据嘴型的变化作为情绪分析的一个指标.
而我的想法是利用嘴的张开比例, 眼睛的睁开程度, 眉毛的倾斜角度作为情绪分析的三个指标. 但是由于人与人长相的差异较大, 五官的也是千差万别, 再加上我的计算方法也比较简单. 所以识别效率并不是很高.
识别规则:
1, 嘴巴张开距离占面部识别框宽度的比例越大, 说明情绪越激动, 可能是非常开心, 也可能是极度愤怒.
2, 眉毛上扬, 17-21 或者 22-26 号特征点距离面部识别框顶部与识别框高度的比值越小, 说明眉毛上扬越厉害, 可表示惊讶, 开心. 眉毛的倾斜角度, 开心时眉毛一般是上扬, 愤怒时皱眉, 同时眉毛下压的比较厉害.
3, 眯眼睛, 人在开怀大笑的时候会不自觉的眯起眼睛, 愤怒或者惊讶的时候会瞪大眼睛.
系统缺点: 不能捕捉细微表情的变化, 只能大致的判断出人的情绪, 开心, 愤怒, 惊讶, 自然.
系统优点: 结构简单, 易于上手.
应用领域: 微笑抓拍, 捕捉瞬间的美好, 缓解儿童自闭症, 交互式游戏开发.
由于人感情的复杂性, 这些表情确实不能完完全全的代表一个人内心深处的情绪波动, 如要提高判断的准确性, 则需要心率检测, 语音处理等综合评价.
二, 开发环境搭建:
1, 安装 VS2015, 因为最新版的 dlib-19.10 需要这个版本的 vscode
2, 安装 opencv(whl 方式安装):
从 pythonlibs 下载需要的版本 whl 文件, 比如(opencv_python?3.3.0+contrib?cp36?cp36m?win_amd64.whl)
然后在本地使用 pip install 安装. 注意文件位置下安装(如: C:\download\xxx.whl)
3, 安装 dlib(whl 方式安装):
在这里下载 dlib 的各种版本的 whl 文件, 然后在根目录下打开 cmd 直接安装即可.
但是为了学习使用 dlib 中的各种 python 实例程序, 还是需要下载一个 dlib 的压缩包.
直接访问 dlib 官网即可下载: http://dlib.net/ml.html
dlib 各种版本的 whl 文件: https://pypi.python.org/simple/dlib/
4, 如果想要使用人脸模型特征标定的话, 还需要一个人脸面部形状预测器, 这个可以通过自己的照片进行训练, 也可以使用 dlib 作者给出的一个训练好的预测器:
点击下载: http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
三, 实施思路
四, 具体步骤
首先是利用 dlib 进行人脸识别:)
- import cv2
- import dlib
- from skimage import io
- # 使用特征提取器 get_frontal_face_detector
- detector = dlib.get_frontal_face_detector()
- # dlib 的 68 点模型, 使用作者训练好的特征预测器
- predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
- # 图片所在路径
- img = io.imread("2.jpg")
- # 生成 dlib 的图像窗口
- win = dlib.image_window()
- win.clear_overlay()
- win.set_image(img)
- # 特征提取器的实例化
- dets = detector(img, 1)
- print("人脸数:", len(dets))
- for k, d in enumerate(dets):
- print("第", k+1, "个人脸 d 的坐标:",
- "left:", d.left(),
- "right:", d.right(),
- "top:", d.top(),
- "bottom:", d.bottom())
- width = d.right() - d.left()
- heigth = d.bottom() - d.top()
- print('人脸面积为:',(width*heigth))
然后实例化一个 shape_predictor 对象, 使用 dlib 作者训练好人脸特征检测器, 进行人脸的特征点标定.
标定的时候使用 opencv 的 circle 方法, 在特征点的坐标上面添加水印, 内容就是特征点的序号和位置.
- # 利用预测器预测
- shape = predictor(img, d)
- # 标出 68 个点的位置
- for i in range(68):
cv2.circle(img, (shape.part(i).x, shape.part(i).y), 4, (0, 255, 0), -1, 8)
cv2.putText(img, str(i), (shape.part(i).x, shape.part(i).y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255))
# 显示一下处理的图片, 然后销毁窗口
cv2.imshow('face', img)
cv2.waitKey(0)
到此, 68 个特征点的信息就获取到了, 下面就需要跟根据这个 68 个特征点的坐标信息, 进行综合 计算, 作为每个表情的判断指标.
根据上面说到的我的判断指标, 先计算嘴巴的张开比例, 由于人离摄像头距离的远近, 导致人脸识别框的大小不一, 故选择比例来作为判断指标.
在选择指标的标准数值之前, 先对多个开心的人脸照片进行分析. 计算开心时的嘴巴张卡比例的平均.
下面是截取对人眉毛的数据处理方法, 对左边眉毛上面的 5 个特征点进行线性拟合, 拟合出一个一次函数直线, 用拟合直线的斜率近似代表眉毛的倾斜程度.
- # 眉毛
- brow_sum = 0 # 高度之和
- frown_sum = 0 # 两边眉毛距离之和
- for j in range(17,21):
- brow_sum+= (shape.part(j).y - d.top()) + (shape.part(j+5).y- d.top())
- frown_sum+= shape.part(j+5).x - shape.part(j).x
line_brow_x.append(shape.part(j).x)
line_brow_y.append(shape.part(j).y)
self.excel_brow_hight.append(round((brow_sum/10)/self.face_width,3))
- self.excel_brow_width.append(round((frown_sum/5)/self.face_width,3))
- brow_hight[0]+= (brow_sum/10)/self.face_width # 眉毛高度占比
- brow_width[0]+= (frown_sum/5)/self.face_width # 眉毛距离占比
- tempx = np.array(line_brow_x)
- tempy = np.array(line_brow_y)
- z1 = np.polyfit(tempx, tempy, 1) # 拟合成一次直线
- self.brow_k = -round(z1[0], 3) # 拟合出曲线的斜率和实际眉毛的倾斜方向是相反的
我计算了 25 个人脸的开心表情的嘴巴张开比例, 嘴巴宽度, 眼睛张开程度, 眉毛倾斜程度, 导入 excel 表格生成折线图:
通过折线图能很明显的看出什么参数可以使用, 什么参数的可信度不高, 什么参数在那个范围内可以作为一个指标.
同样的方法, 计算人愤怒, 惊讶, 自然时的数据折线图.
通过对多个不同表情数据的分析, 得出每个指标的参考值, 可以写出简单的表情分类标准:
- # 分情况讨论
- # 张嘴, 可能是开心或者惊讶
- if round(mouth_higth>= 0.03):
- if eye_hight>= 0.056:
- cv2.putText(im_rd, "amazing", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
- (0, 0, 255), 2, 4)
- else:
- cv2.putText(im_rd, "happy", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
- (0, 0, 255), 2, 4)
- # 没有张嘴, 可能是正常和生气
- else:
- if self.brow_k <= -0.3:
- cv2.putText(im_rd, "angry", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
- (0, 0, 255), 2, 4)
- else:
- cv2.putText(im_rd, "nature", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
- (0, 0, 255), 2, 4)
五, 实际运行效果:
识别之后:
完整项目代码: https://gitee.com/Andrew_Qian/face/blob/master/from_video.py
参考资料:
8 种方法用 Python 实现线性回归, 为你解析最高效选择 https://blog.csdn.net/tMb8Z9Vdm66wH68VX1/article/details/79102425 ;
利用 python 开发, 借助 Dlib 库捕获摄像头中的人脸, 进行实时人脸 68 个特征点标定;
49 款人脸检测 / 识别的 API, 库和软件 https://www.oschina.net/news/43358/49-face-detection-api
来源: https://www.cnblogs.com/qsyll0916/p/8893790.html