dlib表情分析(专注力分数尚在开发)

Dlib 人脸表情识别

dlib作为一个一个c++的开源工具包,应用非常广泛,目前常用于人脸识别以及特征点标定。

1.安装dlib库

安装dlib,dlib依赖于Boost以及cmake

以上两个库都只需要pip install Boost以及pip install cmake即可

但是由于dlib内部集成的是c++环境,所以我们需要安装一个高版本的visual studio,安装时最基本的勾选c++桌面开发,安装完成就可以开始安装dlib

然后直接pip install dlib,下载解压过程可能稍慢,耐心等候。

2. 下载68点标注模型

采用dlib官网给出的训练好的68点标注模型,http://dlib.net/files/

下载解压到你的当前路径,方便引用

3.实现原理

微表情的识别实际简单按照一些动作角度计算并不能做到很精确,人物内心的因素也无法计算在内。

所以这里只是简单的按照一些动作来进行表情识别。

如果当前嘴部上扬的角度过大,可能是惊讶或者高兴,进一步通过眼睛的睁开程度区分

如果当前嘴部张开角度小或者没张开,我们可以暂时认定为自然状态或者愤怒状态,根据眉毛弯曲角度进行进一步的区分。

理论说明,实践开始

import cv2
import dlib
import time
import numpy as np
import mediapipe as mp
class Face():
    def __init__(self):
        /// 加载检测模型
        self. dector = dlib.get_frontal_face_detector()
        /// 加载68点标注模型
        self.predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
    def get_face(self,img):
        """
           获取面部数据
           返回值两个
           一个用于返回表情 一个用于返回68点的坐标
           最后一个来确定是否存在人脸图像
        """
        self.s = {}
        res = self.dector(img)
        # 眉毛直线拟合数据缓冲
        line_brow_x = []
        line_brow_y = []
        # 68点坐标
        dp = [[0 for k in range(2) ]for j in range(68)]
        /// 储存68点数据信息
        if (len(res) != 0):
            for i in range(0,len(res)):
                for id,lm in enumerate(res):
                    self.face_width = lm.right() - lm.left()
                    self.face_higth = lm.top() - lm.bottom()
                    # 计算人脸长度
                    # 使用预测器得到68点数据的坐标
                    shape = self.predictor(img, lm)
                    # 分析点的位置关系来作为表情识别的依据
                    mouth_width = (shape.part(54).x - shape.part(48).x) / self.face_width  # 嘴巴咧开程度
                    mouth_higth = (shape.part(66).y - shape.part(62).y) / self.face_width  # 嘴巴张开程度

                    # 通过两个眉毛上的10个特征点,分析挑眉程度和皱眉程度
                    brow_sum = 0  # 高度之和
                    frown_sum = 0  # 两边眉毛距离之和
                    for j in range(17, 21):
                        brow_sum += (shape.part(j).y - lm.top()) + (shape.part(j + 5).y - lm.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)

                    tempx = np.array(line_brow_x)
                    tempy = np.array(line_brow_y)

                    # np.ployfit(x,a,n)拟合点集a得到n级多项式,其中x为横轴长度
                    z1 = np.polyfit(tempx, tempy, 1)  # 拟合成一次直线
                    self.brow_k = -round(z1[0], 3)  # 拟合出曲线的斜率和实际眉毛的倾斜方向是相反的

                    eye_sum = (shape.part(41).y - shape.part(37).y + shape.part(40).y - shape.part(38).y +
                               shape.part(47).y - shape.part(43).y + shape.part(46).y - shape.part(44).y)
                    eye_hight = (eye_sum / 4) / self.face_width

                   /// 张嘴表情较大,可能是惊讶或者高兴
                    if round(mouth_higth >= 0.03):
                        if eye_hight >= 0.056:
                            self.s = dict(emotion = 'amazing')
                        else:
                            self.s = dict(emotion = 'happy')

                    # 没有张嘴,可能是生气或者自然表情
                    else:
                        if self.brow_k <= -0.5:
                            self.s = dict(emotion = 'angry')
                        else:
                            self.s = dict(emotion = 'nature')
                    for i in range(68):
                        # self.s = ""
                        # self.s += "id: "+ str(i) +","
                        # self.s += "x: " + str(shape.part(i).x) + ","
                        # self.s += "y: " + str(shape.part(i).y)
                        dp[i][0] = shape.part(i).x
                        dp[i][1] = shape.part(i).y
            marks = np.array(dp)
            return self.s,marks,len(res)
        else :
        ///  没有人脸,返回空数据
            return self.s,np.array(dp),len(res)

   

def main():
    # 初始化函数
    CTime = 0
    PTime = 0
    cap = cv2.VideoCapture(0)
    op = Face()
    # cap.set(3, 480)
    # 开启初始的摄像头图像为内置
    while True:
        success, img = cap.read()
        # 获取脸部数据
        emo,vis, len = op.get_face(img)
        # emo字典 返回当前表情   vis返回二维数组 68点的坐标 len代表是否存在人脸
        print(emo)
        print(vis)
        // 计算fps
        CTime = time.time()
        fps = 1 / (CTime - PTime)
        PTime = CTime
        // 显示fps
        cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3)
        # 范围 字体 比例 颜色 速度
        cv2.imshow("Image", img)
        cv2.waitKey(1)

if __name__ == "__main__":
    main()

参考

https://blog.csdn.net/weixin_40277254/article/details/82350220

齐芒行,川锋明!
原文地址:https://www.cnblogs.com/qimang-311/p/15526636.html