计算机视觉(opencv)——嘴部表情检测

实时嘴部表情检测系统:从微笑到哭泣的智能识别


一、项目背景与意义

在计算机视觉领域中,人脸表情识别(Facial Expression Recognition, FER)是一项重要的研究方向。传统的表情识别通常依赖于整张人脸的特征提取,但在很多场景下,仅仅通过嘴部的形变就能准确反映一个人的情绪变化。例如:

  • 驾驶员监控系统中,嘴角上扬代表心情放松,嘴角下垂可能表示疲劳或情绪低落;

  • 课堂学习状态分析中,微笑往往代表专注或兴趣;

  • 智能客服系统中,用户的嘴型可以作为辅助情绪输入。

本文基于 dlib68 点人脸特征定位模型 ,结合 OpenCV 实现实时嘴部表情检测。我们将实现以下功能:

  • 检测人脸;

  • 获取嘴部关键点;

  • 计算嘴部形态参数(MAR 与 MJR);

  • 识别"正常"、"微笑"、"大笑";

  • 拓展实现"哭/悲伤"的检测。


二、算法核心原理

本项目的核心思想是通过计算嘴部的几何比例参数来判断表情。

(1)68 点特征模型

shape_predictor_68_face_landmarks.dat 模型由 dlib 提供,能检测出人脸上的 68 个关键点:

  • 1--17:下颌轮廓;

  • 18--27:眉毛;

  • 28--36:鼻子;

  • 37--48:眼睛;

  • 49--68:嘴部。

嘴部的关键点如下图所示:

复制代码
48 ------ 54:嘴部外轮廓的左右端点
50, 52, 56, 58:嘴部上下边缘点

这些点为我们计算嘴部的几何特征提供了基础。


(2)嘴部高宽比 MAR(Mouth Aspect Ratio)

嘴部高宽比定义为:

MAR = \\frac{(A + B + C) / 3}{D}

其中:

  • A、B、C 分别是上下嘴唇之间的三条垂直距离;

  • D 是嘴的水平宽度(48 到 54 号点)。

在代码中实现如下:

复制代码
def MAR(shape):
    A = euclidean_distances(np.array(shape[50]), np.array(shape[58]))
    B = euclidean_distances(np.array(shape[51]), np.array(shape[57]))
    C = euclidean_distances(np.array(shape[52]), np.array(shape[56]))
    D = euclidean_distances(np.array(shape[48]), np.array(shape[54]))
    return ((A + B + C) / 3) / D

当人嘴张开时,A、B、C 增大,因此 MAR 值上升

  • 正常闭嘴:MAR ≈ 0.2~0.35

  • 微笑:MAR ≈ 0.4

  • 大笑或张嘴:MAR > 0.5


(3)嘴宽与脸颊宽比 MJR(Mouth--Jaw Ratio)

微笑不仅会让嘴角上扬,还会拉宽嘴部。因此,我们再引入一个嘴宽/脸颊宽比:

MJR = \\frac{嘴宽度}{下颌宽度} = \\frac{d_{48,54}}{d_{3,13}}

复制代码
def MJR(shape):
    M = euclidean_distances(np.array(shape[48]), np.array(shape[54]))  # 嘴宽
    J = euclidean_distances(np.array(shape[3]), np.array(shape[13]))   # 下颌宽
    return M / J

一般规律为:

  • 正常:MJR < 0.38

  • 微笑:MJR ≈ 0.40~0.45

  • 大笑:MJR > 0.46


三、系统功能实现与代码解析

完整代码如下:

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

# ------------------- 计算嘴部参数函数 -------------------
def MAR(shape):
    A = euclidean_distances(np.array(shape[50]), np.array(shape[58]))
    B = euclidean_distances(np.array(shape[51]), np.array(shape[57]))
    C = euclidean_distances(np.array(shape[52]), np.array(shape[56]))
    D = euclidean_distances(np.array(shape[48]), np.array(shape[54]))
    return ((A + B + C) / 3) / D

def MJR(shape):
    M = euclidean_distances(np.array(shape[48]), np.array(shape[54]))
    J = euclidean_distances(np.array(shape[3]), np.array(shape[13]))
    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("simsun.ttc", textSize, encoding="utf-8")
    draw.text(position, text, textColor, font=fontStyle)
    return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

# ------------------- 模型加载 -------------------
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()
    rects = detector(frame, 0)
    for rect in rects:
        shape = predictor(frame, rect)
        shape = np.matrix([[p.x, p.y] for p in shape.parts()])

        mar = MAR(shape)
        mjr = MJR(shape)

        result = "正常"
        if mar > 0.5:
            result = "大笑"
        elif mjr > 0.45:
            result = "微笑"

        # 绘制嘴部区域
        mouthHull = cv2.convexHull(shape[48:61])
        cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)

        frame = cv2AddChineseText(frame, f"{result}", (50, 100))

        print(f"MAR: {mar:.3f}\tMJR: {mjr:.3f}\t表情: {result}")

    cv2.imshow("Frame", frame)
    if cv2.waitKey(1) == 27:  # ESC 退出
        break

cv2.destroyAllWindows()
cap.release()

四、运行效果与结果分析

系统运行后,会实时捕获摄像头图像,检测人脸并计算嘴部参数。程序每帧打印 MARMJR 的值,并在窗口中用中文显示当前表情类型。

表情 MAR 范围 MJR 范围 特征描述
正常 0.25--0.35 0.35--0.40 嘴闭合,嘴角自然
微笑 0.35--0.45 0.40--0.45 嘴角上扬,嘴部稍宽
大笑 >0.5 >0.46 嘴张开明显,上下唇分离

通过打印值可以自行调整阈值,以适应不同光线和人脸大小。


五、算法拓展:加入"哭/悲伤"检测

"哭"或"悲伤"表情通常伴随嘴角下垂、嘴部略张。为了检测此类表情,可以结合嘴角坐标高度差。

(1)嘴角高度差计算

设左嘴角点为 48,右嘴角点为 54,嘴部中心点为 51(上唇中点)。

如果嘴角比中点低很多,说明嘴角下垂,可视为"悲伤"或"哭泣"。

计算公式如下:

Sadness = \\frac{y_{48} + y_{54}}{2} - y_{51}

复制代码
def SAD(shape):
    left = shape[48][1, 0]
    right = shape[54][1, 0]
    top = shape[51][1, 0]
    return ((left + right) / 2) - top

一般规律:

  • 正常/微笑:SAD < 0;

  • 哭/悲伤:SAD > 2~5(像素差)。


(2)集成到主循环

加入悲伤检测逻辑:

复制代码
sad_value = SAD(shape)
if mar > 0.5:
    result = "大笑"
elif mjr > 0.45:
    result = "微笑"
elif sad_value > 3:
    result = "哭泣/悲伤"
else:
    result = "正常"

通过组合三个特征(MAR、MJR、SAD),可以区分更多情绪状态。


六、性能优化与注意事项

  1. 关键点模型加载时间

    • shape_predictor_68_face_landmarks.dat 文件较大(约 100MB),建议在程序开头加载一次;

    • 若需速度更快,可使用 shape_predictor_5_face_landmarks.dat 轻量模型,仅包含眼睛和嘴角特征。

  2. 摄像头分辨率

    • 默认分辨率可能较低(640×480),可以通过:

      复制代码
      cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
      cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

      提升检测精度。

  3. 光照条件

    • 建议使用均匀光线,避免强背光;

    • 可加入 cv2.equalizeHist 对图像亮度进行均衡化。

  4. 多线程优化

    • 如果需要在实时监控系统中使用,可将检测与绘图分离至两个线程,提高帧率。

七、应用场景拓展

应用场景 功能说明
驾驶员监控 检测驾驶员微笑/打哈欠,判断疲劳或情绪
教育场景 检测学生表情变化,分析学习兴趣
智能客服 根据客户表情动态调整语气或推荐内容
互动娱乐 表情控制游戏角色(如微笑触发动作)
医疗康复 辅助评估患者面部肌肉恢复情况

八、未来方向

未来可结合深度学习模型(如 CNN + LSTM)实现更精准的多情绪识别,同时加入眼部、眉毛等特征,实现更全面的情绪判断。此外,还可采用面部 3D 重建或光流分析,识别更细微的表情动态。


九、总结

本文从嘴部几何特征出发,通过计算 MAR(高宽比)MJR(嘴宽比),实现了实时的"微笑"、"大笑"、"正常"表情识别,并扩展实现了"哭/悲伤"的检测。该系统具有以下优点:

  • 轻量级:无需深度学习模型;

  • 实时性强:CPU 即可流畅运行;

  • 可扩展性高:容易加入更多表情类型。

这种基于几何分析的嘴部表情识别方法,虽然精度略低于深度神经网络,但在嵌入式设备、实时监控、教学分析等场景中具备极高的实用价值。


完整检测公式汇总

参数 定义 功能
MAR 嘴部高度 / 宽度 检测张嘴程度
MJR 嘴宽 / 下颌宽 检测微笑程度
SAD 嘴角高度差 检测悲伤/哭泣

通过组合判断:

复制代码
if mar > 0.5:
    表情 = "大笑"
elif mjr > 0.45:
    表情 = "微笑"
elif sad_value > 3:
    表情 = "哭泣/悲伤"
else:
    表情 = "正常"
相关推荐
星马梦缘21 小时前
强化学习实战7——用决策树打赢星际争霸II
人工智能·决策树·强化学习·deepmind·星际争霸·sc2
CoderJia程序员甲21 小时前
GitHub 热榜项目 - 日榜(2026-04-11)
人工智能·ai·大模型·github·ai教程
ChatInfo21 小时前
Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模
数据库·人工智能·mysql
lifallen1 天前
Flink Agents:Python 执行链路与跨语言 Actor (PyFlink Agent)
java·大数据·人工智能·python·语言模型·flink
小二·1 天前
2026年4月技术热点深度解析:AI智能体攻防、量子安全与云原生新纪元
人工智能·安全·云原生
江瀚视野1 天前
京东健康综合门诊望京开业,京东医疗路在何方?
大数据·人工智能
飞凌嵌入式1 天前
如何用JishuShell在RK3588核心板上快速部署OpenClaw?
arm开发·人工智能·嵌入式硬件·openclaw
IT_陈寒1 天前
Vue的响应式更新把我坑惨了,原来是这个问题
前端·人工智能·后端
Tom·Ge1 天前
告别“猜谜式编程”!详解规范驱动开发(SDD)在企业AI开发中的最佳实践
人工智能·驱动开发
gyx_这个杀手不太冷静1 天前
大人工智能时代下前端界面全新开发模式的思考(一)
前端·人工智能·ai编程