實時嘴部表情檢測系統:從微笑到哭泣的智能識別
一、項目背景與意義
在計算機視覺領域中,人臉表情識別(Facial Expression Recognition, FER)是一項重要的研究方向。傳統的表情識別通常依賴於整張人臉的特徵提取,但在很多場景下,僅僅通過嘴部的形變就能準確反映一個人的情緒變化。例如:
- 駕駛員監控系統中,嘴角上揚代表心情放鬆,嘴角下垂可能表示疲勞或情緒低落;
- 課堂學習狀態分析中,微笑往往代表專注或興趣;
- 智能客服系統中,用户的嘴型可以作為輔助情緒輸入。
本文基於 dlib 的 68 點人臉特徵定位模型,結合 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()
四、運行效果與結果分析
系統運行後,會實時捕獲攝像頭圖像,檢測人臉並計算嘴部參數。程序每幀打印 MAR 和 MJR 的值,並在窗口中用中文顯示當前表情類型。
|
表情
|
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),可以區分更多情緒狀態。
六、性能優化與注意事項
- 關鍵點模型加載時間
shape_predictor_68_face_landmarks.dat文件較大(約 100MB),建議在程序開頭加載一次;- 若需速度更快,可使用
shape_predictor_5_face_landmarks.dat輕量模型,僅包含眼睛和嘴角特徵。
- 攝像頭分辨率
- 默認分辨率可能較低(640×480),可以通過:
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
提升檢測精度。
- 光照條件
- 建議使用均勻光線,避免強背光;
- 可加入
cv2.equalizeHist對圖像亮度進行均衡化。
- 多線程優化
- 如果需要在實時監控系統中使用,可將檢測與繪圖分離至兩個線程,提高幀率。
七、應用場景拓展
|
應用場景
|
功能説明
|
|
駕駛員監控
|
檢測駕駛員微笑/打哈欠,判斷疲勞或情緒
|
|
教育場景
|
檢測學生表情變化,分析學習興趣
|
|
智能客服
|
根據客户表情動態調整語氣或推薦內容
|
|
互動娛樂
|
表情控制遊戲角色(如微笑觸發動作)
|
|
醫療康復
|
輔助評估患者面部肌肉恢復情況
|
八、未來方向
未來可結合深度學習模型(如 CNN + LSTM)實現更精準的多情緒識別,同時加入眼部、眉毛等特徵,實現更全面的情緒判斷。此外,還可採用面部 3D 重建或光流分析,識別更細微的表情動態。
九、總結
本文從嘴部幾何特徵出發,通過計算 MAR(高寬比) 與 MJR(嘴寬比),實現了實時的“微笑”、“大笑”、“正常”表情識別,並擴展實現了“哭/悲傷”的檢測。該系統具有以下優點:
- 輕量級:無需深度學習模型;
- 實時性強:CPU 即可流暢運行;
- 可擴展性高:容易加入更多表情類型。
這種基於幾何分析的嘴部表情識別方法,雖然精度略低於深度神經網絡,但在嵌入式設備、實時監控、教學分析等場景中具備極高的實用價值。
✅ 完整檢測公式彙總
|
參數
|
定義
|
功能
|
|
|
嘴部高度 / 寬度
|
檢測張嘴程度
|
|
|
嘴寬 / 下頜寬
|
檢測微笑程度
|
|
|
嘴角高度差
|
檢測悲傷/哭泣
|
通過組合判斷:
if mar > 0.5:
表情 = "大笑"
elif mjr > 0.45:
表情 = "微笑"
elif sad_value > 3:
表情 = "哭泣/悲傷"
else:
表情 = "正常"