實時嘴部表情檢測系統:從微笑到哭泣的智能識別


一、項目背景與意義

在計算機視覺領域中,人臉表情識別(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 輕量模型,僅包含眼睛和嘴角特徵。
  1. 攝像頭分辨率
  • 默認分辨率可能較低(640×480),可以通過:
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

提升檢測精度。

  1. 光照條件
  • 建議使用均勻光線,避免強背光;
  • 可加入 cv2.equalizeHist 對圖像亮度進行均衡化。
  1. 多線程優化
  • 如果需要在實時監控系統中使用,可將檢測與繪圖分離至兩個線程,提高幀率。

七、應用場景拓展

應用場景

功能説明

駕駛員監控

檢測駕駛員微笑/打哈欠,判斷疲勞或情緒

教育場景

檢測學生表情變化,分析學習興趣

智能客服

根據客户表情動態調整語氣或推薦內容

互動娛樂

表情控制遊戲角色(如微笑觸發動作)

醫療康復

輔助評估患者面部肌肉恢復情況


八、未來方向

未來可結合深度學習模型(如 CNN + LSTM)實現更精準的多情緒識別,同時加入眼部、眉毛等特徵,實現更全面的情緒判斷。此外,還可採用面部 3D 重建或光流分析,識別更細微的表情動態。


九、總結

本文從嘴部幾何特徵出發,通過計算 MAR(高寬比)MJR(嘴寬比),實現了實時的“微笑”、“大笑”、“正常”表情識別,並擴展實現了“哭/悲傷”的檢測。該系統具有以下優點:

  • 輕量級:無需深度學習模型;
  • 實時性強:CPU 即可流暢運行;
  • 可擴展性高:容易加入更多表情類型。

這種基於幾何分析的嘴部表情識別方法,雖然精度略低於深度神經網絡,但在嵌入式設備、實時監控、教學分析等場景中具備極高的實用價值。


完整檢測公式彙總

參數

定義

功能

MAR

嘴部高度 / 寬度

檢測張嘴程度

MJR

嘴寬 / 下頜寬

檢測微笑程度

SAD

嘴角高度差

檢測悲傷/哭泣

通過組合判斷:

if mar > 0.5:
    表情 = "大笑"
elif mjr > 0.45:
    表情 = "微笑"
elif sad_value > 3:
    表情 = "哭泣/悲傷"
else:
    表情 = "正常"