当前位置: 首页 > article >正文

【进阶OpenCV】 (19)-- Dlib库 --人脸表情识别

文章目录

  • 表情识别
    • 一、原理
    • 二、代码实现
      • 1. 摄像头前预处理
      • 2. 计算嘴唇变化
      • 3. 绘制嘴唇轮廓
      • 4. 显示结果
      • 5. 完整代码展示
  • 总结

表情识别

目标:识别人物的喜悦状态。

一、原理

我们在对一张人脸图片进行关键点定位后,得到每个关键点的位置:

在这里插入图片描述

比如嘴唇,想象一下当一个人大笑的时候,嘴的大小是不是会发生变化呢,上嘴唇关键点与下嘴唇关键点的距离是不是会变化呐?

这样我们就可以通过变化程度来简单的判断人物体现的心情。

唇部关键点

在这里插入图片描述

人在微笑时,嘴角会上扬,嘴的宽度和与整个脸颊(下颌)的宽度之比变大。

二、代码实现

1. 摄像头前预处理

  1. 构造脸部位置检测器HOG ----> 检测人脸
  2. dlib.shape_predictor载入模型(加载预测器)---- > 获取关键点
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()  # 如果正确读取,ret为True
    if not ret:
        print("不能读取摄像头")
        break
    faces = detector(frame, 0)  # 检测人脸

2. 计算嘴唇变化

  • 计算嘴的宽高比

使用euclidean_distances()函数方法,计算两个数据点之间的欧几里得距离,即两点之间的直线距离。

from sklearn.metrics.pairwise import euclidean_distances
def MAR(shape): # 计算嘴的宽高比
    x = shape[50]
    y = shape[50].reshape(1,2)

    A = euclidean_distances(shape[50].reshape(1,2),shape[58].reshape(1,2))
    B = euclidean_distances(shape[51].reshape(1, 2), shape[57].reshape(1, 2))
    C = euclidean_distances(shape[52].reshape(1, 2), shape[56].reshape(1, 2))
    D = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2))
    return ((A+B+C)/3)/D
  • 计算嘴宽度、脸颊宽度的比值
def MJR(shape): # 计算嘴宽度、脸颊宽度的比值
    M = euclidean_distances(shape[48].reshape(1,2),shape[54].reshape(1,2)) # 嘴宽度
    J = euclidean_distances(shape[3].reshape(1, 2), shape[13].reshape(1, 2)) # 下颌的宽度
    return M/J
  • 代码
for face in faces:
    shape = predictor(frame,face)
    shape = np.array([[p.x,p.y] for p in shape.parts()])
    mar = MAR(shape) # 绘制右眼凸包
    mjr = MJR(shape) # 绘制左眼凸包
    result = "正常"
    print("mar",mar,"\tmjr",mjr)
    if mar > 0.5:
        result = "大笑"
    elif mjr > 0.45:
        result = "微笑"

3. 绘制嘴唇轮廓

绘制嘴唇轮廓,并将表情检测结果显示在图像上:

def cv2ADDChineseText(img,text,position,textColor=(0,255,0),textSize=30):
    """向图片中添加中文"""
    if (isinstance(img,np.ndarray)):
        img = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)

    fontStyle = ImageFont.truetype("simfang.ttf",textSize,encoding="Utf-8")
    draw.text(position,text,textColor,font=fontStyle)
    return cv2.cvtColor(np.asarray(img),cv2.COLOR_BGR2RGB)
mouthHull = cv2.convexHull(shape[48:61]) # 计算凸包
frame = cv2ADDChineseText(frame, result, mouthHull[0, 0])  # 多人脸
cv2.drawContours(frame,[mouthHull],-1,(0,255,0),1)

4. 显示结果

    cv2.imshow("Frame",frame)
    if cv2.waitKey(1) == 27:
        break
cv2.destroyAllWindows()
cap.release()

5. 完整代码展示

import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image,ImageDraw,ImageFont

def MAR(shape): # 计算嘴的宽高比
    x = shape[50]
    y = shape[50].reshape(1,2)

    A = euclidean_distances(shape[50].reshape(1,2),shape[58].reshape(1,2))
    B = euclidean_distances(shape[51].reshape(1, 2), shape[57].reshape(1, 2))
    C = euclidean_distances(shape[52].reshape(1, 2), shape[56].reshape(1, 2))
    D = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2))
    return ((A+B+C)/3)/D

def MJR(shape): # 计算嘴宽度、脸颊宽度的比值
    M = euclidean_distances(shape[48].reshape(1,2),shape[54].reshape(1,2)) # 嘴宽度
    J = euclidean_distances(shape[3].reshape(1, 2), shape[13].reshape(1, 2)) # 下颌的宽度
    return M/J

def cv2ADDChineseText(img,text,position,textColor=(0,255,0),textSize=30):
    """向图片中添加中文"""
    if (isinstance(img,np.ndarray)):
        img = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)

    fontStyle = ImageFont.truetype("simfang.ttf",textSize,encoding="Utf-8")
    draw.text(position,text,textColor,font=fontStyle)
    return cv2.cvtColor(np.asarray(img),cv2.COLOR_BGR2RGB)

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()  # 如果正确读取,ret为True
    if not ret:
        print("不能读取摄像头")
        break
    faces = detector(frame, 0)  # 检测人脸

    for face in faces:
        shape = predictor(frame,face)
        shape = np.array([[p.x,p.y] for p in shape.parts()])
        mar = MAR(shape) # 绘制右眼凸包
        mjr = MJR(shape) # 绘制左眼凸包
        result = "正常"
        print("mar",mar,"\tmjr",mjr)
        if mar > 0.5:
            result = "大笑"
        elif mjr > 0.45:
            result = "微笑"
        mouthHull = cv2.convexHull(shape[48:61])

        frame = cv2ADDChineseText(frame, result, mouthHull[0, 0])  # 多人脸
        cv2.drawContours(frame,[mouthHull],-1,(0,255,0),1)

    cv2.imshow("Frame",frame)
    if cv2.waitKey(1) == 27:
        break
cv2.destroyAllWindows()
cap.release()

总结

本篇介绍了如何通过计算面部关键点的变化情况,来判断人脸的表情变化情况。


http://www.kler.cn/a/355222.html

相关文章:

  • SpringBoot + vue 管理系统
  • 【Compose multiplatform教程18】多平台资源的设置和配置
  • Retrofit和rxjava 实现窜行请求,并行请求,循环多次请求,递归请求,错误重试
  • 拆解Java中——“ 注解 ”和“ 注释 ” 的一切区别Ⅱ
  • 华为麦芒5(安卓6)termux记录 使用ddns-go,alist
  • C#运动控制系统:雷赛控制卡实用完整例子 C#雷赛开发快速入门 C#雷赛运动控制系统实战例子 C#快速开发雷赛控制卡
  • 删除链表的倒数第 N 个结点 | LeetCode-19 | 双指针 | 递归 | 栈 | 四种方法
  • 数据库初体验
  • 淘系商品详情数据封装接口(API接口)json数据格式分析
  • srsRAN 4G设置的笔记
  • Cocos Creator 原生Android项目打 aab 包,升级到Android14(API 34)
  • 想让前后端交互更轻松?alovajs了解一下?
  • Java爬虫:从入门到精通实战指南
  • apache pulsar 安装最新版本, docker安装pulsar3.3.2
  • unity学习笔记-Text mesh Pro
  • web API基础
  • 【大数据】Hive快速入门
  • 【Linux】Linux常见指令及权限理解
  • TCP——Socket
  • linux的学习第二天
  • 基于Opencv中的DNN模块实现图像/视频的风格迁移
  • mysql-数据库的操作
  • 交叉熵损失 在PyTorch 中的计算过程
  • MySQL-CRUD-基础-(详解) ┗( ▔, ▔ )┛
  • PostgreSQL学习笔记十三:常用函数
  • Flutter框架学习计划