FER 人脸情绪识别系统

一、主要的流程

FER 人脸情绪识别系统

二、主要步骤:

1.我们可以通过调用dlib这个库 使用特征提取器get_frontal_face_detector
以及使用训练好的特征预测器  从而得到dlib 的68点模型,为我们的情绪识别提供了很大帮助

# 使用特征提取器get_frontal_face_detector
    self.detector = dlib.get_frontal_face_detector()
    # dlib 的68点模型,使用训练好的特征预测器
    self.predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

2.  

首先  建cv2摄像头对象 之后进行分帧及灰度处理

之所以进行灰度处理是为了减小图像原始数据量,便于后续处理时计算量更少,因为情绪识别的图像处理一般不需要对彩色图像的RGB三个分量都进行处理

之后利用dlib进行检测人脸  并通过预测器得到68点数据的坐标

# cv2摄像头对象,这里使用电脑自带摄像头,如果接了外部摄像头,则自动切换到外部摄像头
self.cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
# 设置视频参数,propId设置的视频参数,value设置的参数值
self.cap.set(3, 480)

# cap.isOpened() 返回true/false 检查初始化是否成功
while (True):

   
# cap.read()
    #
返回两个值:
   
# 一个布尔值true/false,用来判断读取视频是否成功/是否到视频末尾
   
# 图像对象,图像的三维矩阵
   
flag, im_rd = self.cap.read()

   
# 每帧数据延时1ms,延时为0读取的是静态帧
   
k = cv2.waitKey(30)
   
# 取灰度
   
img_gray = cv2.cvtColor(im_rd, cv2.COLOR_RGB2GRAY)

# 使用人脸检测器检测每一帧图像中的人脸。并返回人脸数rects
   
faces = self.detector(img_gray, 0)
   
# 待会要显示在屏幕上的字体
   
font = cv2.FONT_HERSHEY_SIMPLEX
   
# 如果检测到人脸
   
if (len(faces) != 0):
       
# 对每个人脸都标出68个特征点
           
# enumerate方法同时返回数据对象的索引和数据,k为索引,dfaces中的对象
       
for k, d in enumerate(faces):
           
# 用红色矩形框出人脸
           
cv2.rectangle(im_rd, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255))
           
# print(d.top())
            #
计算人脸热别框边长
           
self.face_width = d.right() - d.left()
           
# 使用预测器得到68点数据的坐标
           
shape = self.predictor(im_rd, d)
   3.
到1971年,这两个人研究了 6 种基本表情 (即高兴、悲伤、惊讶、恐惧、愤怒和厌恶 ) ,并系统地建立了上千幅不同的人脸表情图象库。

通过这个表格 我们可以看到 不同的表情对应了脸部不同的运动特征。如惊讶时 一般嘴巴张开 眉毛抬高 眼睛睁大

FER 人脸情绪识别系统

4.

FER 人脸情绪识别系统

FER 人脸情绪识别系统

首先来看一下对于眼睛睁开程度的测定,通过41 37 40 38 等坐标的运算 我们可以得到  眼睛睁开距离与识别框高度之比,我们也可以得到以下参数

mouse_width  # 嘴巴宽度与识别框宽度之比
mouse_height  # 嘴巴高度与识别框高度之比
k  # 眉毛的倾斜方向
eyebrow_height  # 眉毛高度与识别框高度之比
eyebrow_spacing  # 眉毛间距与识别框高度之比
eye  # 眼睛睁开距离与识别框高度之比
eye_long   # 眼睛长度
mouth_higth # 嘴巴外圈张开

mouth_xia  # 嘴巴下

我们计算了CK+这个人脸表情的数据集里 开心表情的嘴巴张开比例、嘴巴宽度、眉毛倾斜程度等特征,并导入excel表格生成折线图:

FER 人脸情绪识别系统

通过折线图可以很明显的看出什么参数可以使用,什么参数的可信度不高,什么参数在那个范围内可以作为一个指标。

我们分析了并结合平均值 极值 方差 稳定性等各个方面以及不同表情之间主要突出特征的主成分分析,通过对多个不同表情数据的分析,得出每个指标的参考值,可以写出简单的表情分类标准。

得到了以下代码

if (eye_long <= 0.02 and 0.13 0.21 and mouth_higth< 0.04

    and 0 <= mouth_xia_ <= 0.1 and 0.350.43 and

    eye_hight <= 0.08):
    cv2.putText(im_rd, "angry", (d.left(), d.bottom() + 20),  cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2, 4)
 

elif 0.03 <= mouth_higth <= 0.3 and (0.3 <= mouth_width <= 0.55)

        and (0.08 <= mouth_xia_ <= 0.2 and 0.20.3 and  0.10.22):
    cv2.putText(im_rd,
"happy", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2, 4)

elif 0.04 0.11 and 0.15 <= mouth_higth_w and 0.20.4

         and 00.2 and 0.040.2 and 0.1         # or ((mouth_higth <= 0.1) and (0.12 < eye_hight)):
   
cv2.putText(im_rd, "surprise", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
                (
0, 0, 255), 2, 4)


elif ((0.03 <= eye_hight <= 0.08) and 0.27 <= brow_k <= 0.35 and

       mouth_xia_ < 0.1 and 0.050.15 and 0.240.41):
       
# or (0.3 <= mouth_width and eye_hight <= 0.03):

   
cv2.putText(im_rd, "sadness", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
                (
0, 0, 255), 2, 4)
elif mouth_xia_<0 and 0.250.4 and 0.040.1 and 0.3
    cv2.putText(im_rd,
"nature", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
                (
0, 0, 255), 2, 4)

虽然简单的表情可以识别出来,但是一些复杂的表情识别准确率较低,所以我们决定暂时放弃了对这种方法的探索

 于是我们又寻求了另一种分类方式Knn

KNN的全称是K Nearest Neighbors,意思是K个最近的邻居,从这个名字我们就能看出一些KNN算法的蛛丝马迹。K个最近邻居,毫无疑问,K的取值肯定是至关重要的。那么最近的邻居又是怎么回事呢?其实,KNN的原理就是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别。听起来有点迷,我们还是来看看图吧。

FER 人脸情绪识别系统

图中绿色的点就是我们要预测的那个点,假设K=3。那么KNN算法就会找到与它距离最近的三个点(这里用圆圈把它圈起来了),看看哪种类别多一些,比如这个例子中是蓝色三角形多一些,新来的绿色点就归类到蓝三角了。

但是,当K=5的时候,判定就变成不一样了。这次变成红圆多一些,所以新来的绿点被归类成红圆。从这个例子中,我们就能看得出K的取值是很重要的。

FER 人脸情绪识别系统

就先介绍到这了

这是我们的一个课程设计

我们一步一步探索 表情识别部分由sklearn knn模型识别 

我们也制作了交互页面gui 包括 摄像头实时识别及图片表情识别

完整代码 可私信我

上一篇:2020-2021 “Orz Panda” Cup Programming Contest


下一篇:期末考试Day1