在人工智能技术飞速发展的今天,计算机视觉作为核心分支之一,已经深度融入安防监控、驾驶辅助、人机交互、智能美颜等众多生活与工业场景。人脸作为人类最具辨识度的生物特征载体,其检测、关键点定位、属性分析与状态识别技术,成为计算机视觉领域的研究热点。

本文将基于OpenCVDlibScikit-learn等主流开源库,从零构建一套集驾驶员疲劳检测面部表情(微笑 / 大笑)识别年龄与性别预测于一体的人脸智能分析系统。我们将拆解核心算法原理,分步实现功能模块,并完成多任务融合,最终实现一个实时、高效、实用的视觉分析工具。全文将从环境搭建、核心理论、代码实现、功能融合到效果优化,全方位讲解技术细节,帮助开发者快速掌握人脸视觉分析的核心技能。

二、核心技术原理

本系统融合了人脸检测68 点关键点定位眼部纵横比(EAR)嘴巴纵横比(MAR)深度学习年龄性别预测五大核心技术,我们先逐一讲解原理:

1. 68 点人脸关键点定位

Dlib 提供的 68 点人脸关键点模型,能够精准定位人脸的眉毛、眼睛、鼻子、嘴巴、脸部轮廓等关键区域。关键点索引划分:

  • 右眼:36~41
  • 左眼:42~47
  • 嘴巴:48~67
  • 脸部轮廓:0~16

通过这些关键点坐标,我们可以计算眼部、嘴巴的几何特征,实现状态识别。

2. 眼部纵横比(EAR)- 疲劳检测核心

疲劳检测的核心是判断驾驶员是否闭眼,Eye Aspect Ratio(EAR) 是行业通用标准算法。原理:通过计算眼睛垂直距离与水平距离的比值,判断眼睛开合程度。公式:EAR=2×∣∣p1​−p4​∣∣∣∣p2​−p6​∣∣+∣∣p3​−p5​∣∣​当 EAR 值低于阈值(本文 0.28)时,判定为闭眼;持续多帧闭眼则判定为疲劳驾驶,触发警报。

3. 嘴巴纵横比(MAR)与嘴巴脸型比(MLR)- 表情识别

通过嘴巴关键点计算Mouth Aspect Ratio(MAR),判断嘴巴开合程度;结合Mouth-Lip Ratio(MLR),区分微笑大笑

  • MAR > 0.5:判定为大笑;
  • MLR > 0.45:判定为微笑;
  • 其余状态:正常表情。

4. 深度学习年龄性别预测

基于 Caffe 框架训练的深度学习模型,对人脸区域进行预处理(Blob 转换),输入网络后输出年龄区间和性别的概率分布,取最大概率值作为预测结果。

二、分模块代码实现

我们将系统拆分为疲劳检测模块表情识别模块年龄性别预测模块CNN 高精度人脸检测模块,分步实现。

模块一:驾驶员疲劳检测系统

疲劳检测是驾驶安全的核心功能,通过实时计算眼部 EAR 值,判断闭眼状态并触发警报。

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

# 计算眼部纵横比EAR
def eye_aspect_ratio(eye):
    A = euclidean_distances(eye[1].reshape(1, 2), eye[5].reshape(1, 2))
    B = euclidean_distances(eye[2].reshape(1, 2), eye[4].reshape(1, 2))
    C = euclidean_distances(eye[0].reshape(1, 2), eye[3].reshape(1, 2))
    ear = ((A + B) / 2.0) / C
    return ear

# OpenCV中文绘制函数
def cv2AddChineseText(img, text, position, textColor=(255, 0, 0), textSize=50):
    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_BGR2RGB)

# 绘制眼睛轮廓
def drawEye(eye):
    eyeHull = cv2.convexHull(eye)
    cv2.drawContours(frame, [eyeHull], -1, (0, 255, 0), -1)

# 初始化检测器
COUNTER = 0  # 闭眼帧数计数器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
cap = cv2.VideoCapture('smile.mp4')  # 视频/摄像头

while True:
    ret, frame = cap.read()
    if not ret: break
    faces = detector(frame, 0)
    for face in faces:
        # 获取68关键点
        shape = predictor(frame, face)
        shape = np.array([[p.x, p.y] for p in shape.parts()])
        # 提取左右眼
        rightEye = shape[36:42]
        leftEye = shape[42:48]
        # 计算EAR均值
        rightEAR = eye_aspect_ratio(rightEye)
        leftEAR = eye_aspect_ratio(leftEye)
        ear = (leftEAR + rightEAR) / 2.0

        # 疲劳判断逻辑
        if ear < 0.28:
            COUNTER += 1
            if COUNTER >= 40:  # 持续40帧闭眼 → 危险
                frame = cv2AddChineseText(frame, '!!!!!危险!!!!!', (250, 250))
        else:
            COUNTER = 0
            drawEye(leftEye)
            drawEye(rightEye)
            info = 'EAR: {:.2f}'.format(ear[0][0])
            frame = cv2AddChineseText(frame, info, (10, 10))
    cv2.imshow('Frame', frame)
    if cv2.waitKey(1) == 27: break

cv2.destroyAllWindows()
cap.release()

功能说明:实时检测眼睛开合状态,持续闭眼触发红色警报文字,睁眼时绘制绿色眼睛轮廓并显示 EAR 数值。

模块二:年龄与性别预测

基于 OpenCV DNN 模块加载深度学习模型,实现人脸属性快速预测:

import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np

# 模型路径配置
faceProto = 'model/opencv_face_detector.pbtxt'
faceModel = 'model/opencv_face_detector_uint8.pb'
ageProto = 'model/deploy_age.prototxt'
ageModel = 'model/age_net.caffemodel'
genderProto = 'model/deploy_gender.prototxt'
genderModel = 'model/gender_net.caffemodel'

# 加载模型
ageNet = cv2.dnn.readNet(ageModel, ageProto)
genderNet = cv2.dnn.readNet(genderModel, genderProto)
faceNet = cv2.dnn.readNet(faceModel, faceProto)

# 标签定义
ageList = ['0-2岁', '4-8岁', '20-25岁', '38-43岁', '48-53岁', '60-70岁', '80-90岁', '91-100岁']
genderList = ['男性', '女性']
mean = (78.4263377603, 87.7689143744, 114.895847746)

# 人脸检测函数
def getBoxes(net, frame):
    frameHeight, frameWidth = frame.shape[:2]
    blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), [104, 117, 123], True, False)
    net.setInput(blob)
    detections = net.forward()
    faceBoxes = []
    for i in range(detections.shape[2]):
        confidence = detections[0, 0, i, 2]
        if confidence > 0.7:
            x1 = int(detections[0, 0, i, 3] * frameWidth)
            y1 = int(detections[0, 0, i, 4] * frameHeight)
            x2 = int(detections[0, 0, i, 5] * frameWidth)
            y2 = int(detections[0, 0, i, 6] * frameHeight)
            faceBoxes.append([x1, y1, x2, y2])
            cv2.rectangle(frame, (x1, y1), (x2, y2), (0,255,0), 2)
    return frame, faceBoxes

# 中文绘制函数
def cv2AddChineseText(img, text, position, textColor=(255,0,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_BGR2RGB)

# 主程序
cap = cv2.VideoCapture('smile.mp4')
while True:
    _, frame = cap.read()
    if not ret: break
    frame = cv2.flip(frame, 1)
    frame, faceBoxes = getBoxes(faceNet, frame)
    if not faceBoxes:
        print("未检测到人脸")
        continue
    for faceBox in faceBoxes:
        x1, y1, x2, y2 = faceBox
        face = frame[y1:y2, x1:x2]
        blob = cv2.dnn.blobFromImage(face, 1.0, (227,227), mean)
        # 性别预测
        genderNet.setInput(blob)
        gender = genderList[genderNet.forward()[0].argmax()]
        # 年龄预测
        ageNet.setInput(blob)
        age = ageList[ageNet.forward()[0].argmax()]
        # 绘制结果
        result = f'{gender},{age}'
        frame = cv2AddChineseText(frame, result, (x1, y1-30))
    cv2.imshow('result', frame)
    if cv2.waitKey(1) == 27: break
cv2.destroyAllWindows()
cap.release()

功能说明:自动框选人脸,在人脸上方显示性别和年龄区间,支持视频 / 摄像头实时预测。

模块三:表情识别(微笑 / 大笑)

基于嘴巴关键点计算 MAR 和 MLR 值,实现表情分类:

# 计算嘴巴纵横比MAR
def MAR(shape):
    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

# 计算嘴巴脸型比MLR
def MLR(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

逻辑说明:结合 MAR 和 MLR 双阈值判断,精准区分正常、微笑、大笑三种状态,并绘制嘴巴轮廓。

模块四:CNN 高精度人脸检测

Dlib 的 CNN 模型针对复杂场景(多人、侧脸、遮挡)优化,检测精度远超传统检测器:

import dlib
import cv2

# 加载CNN人脸检测器
cnn_face_detector = dlib.cnn_face_detection_model_v1('mmod_human_face_detector.dat')
img = cv2.imread('qunxiang2.png')
# 检测人脸
faces = cnn_face_detector(img, 0)
for d in faces:
    rect = d.rect
    cv2.rectangle(img, (rect.left(), rect.top()), (rect.right(), rect.bottom()), (0,255,0), 3)
cv2.imshow('CNN人脸检测', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

功能说明:适用于多人合照、复杂背景下的人脸检测,鲁棒性极强。

三、多模块融合:一体化智能人脸分析系统

我们将上述所有模块整合,实现疲劳检测 + 表情识别 + 年龄性别预测同步运行,这也是本项目的最终形态:

# 一体化人脸智能分析系统
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import dlib
from sklearn.metrics.pairwise import euclidean_distances

# 模型路径配置
faceProto = 'model/opencv_face_detector.pbtxt'
faceModel = 'model/opencv_face_detector_uint8.pb'
ageProto = 'model/deploy_age.prototxt'
ageModel = 'model/age_net.caffemodel'
genderProto = 'model/deploy_gender.prototxt'
genderModel = 'model/gender_net.caffemodel'

# 核心计算函数
def MAR(shape):
    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 MLR(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 eye_aspect_ratio(eye):
    A = euclidean_distances(eye[1].reshape(1,2), eye[5].reshape(1,2))
    B = euclidean_distances(eye[2].reshape(1,2), eye[4].reshape(1,2))
    C = euclidean_distances(eye[0].reshape(1,2), eye[3].reshape(1,2))
    return ((A + B) / 2.0) / C

# 加载模型
ageNet = cv2.dnn.readNet(ageModel, ageProto)
genderNet = cv2.dnn.readNet(genderModel, genderProto)
faceNet = cv2.dnn.readNet(faceModel, faceProto)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

# 标签配置
ageList = ['0-2岁', '4-8岁', '20-25岁', '38-43岁', '48-53岁', '60-70岁', '80-90岁', '91-100岁']
genderList = ['女性', '男性']
mean = (78.4263377603, 87.7689143744, 114.895847746)

# 工具函数
def getBoxes(net, frame):
    h, w = frame.shape[:2]
    blob = cv2.dnn.blobFromImage(frame, 1.0, (300,300), [104,117,123], True, False)
    net.setInput(blob)
    dets = net.forward()
    boxes = []
    for i in range(dets.shape[2]):
        conf = dets[0,0,i,2]
        if conf>0.7:
            x1 = int(dets[0,0,i,3]*w)
            y1 = int(dets[0,0,i,4]*h)
            x2 = int(dets[0,0,i,5]*w)
            y2 = int(dets[0,0,i,6]*h)
            boxes.append([x1,y1,x2,y2])
            cv2.rectangle(frame,(x1,y1),(x2,y2),(0,255,0),2)
    return frame, boxes

def cv2AddChineseText(img, text, pos, color=(255,0,0), size=30):
    if isinstance(img, np.ndarray):
        img = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype('simsun.ttc', size, encoding='utf-8')
    draw.text(pos, text, color, font=font)
    return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)

def drawEye(eye, frame):
    hull = cv2.convexHull(eye)
    cv2.drawContours(frame, [hull], -1, (0,255,0), -1)

# 主程序
COUNTER = 0
cap = cv2.VideoCapture('smile.mp4')
while True:
    ret, frame = cap.read()
    if not ret: break
    frame = cv2.flip(frame,1)
    frame, boxes = getBoxes(faceNet, frame)
    if not boxes:
        cv2.imshow('人脸智能分析系统', frame)
        continue
    
    # Dlib关键点检测
    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 = MLR(shape)
        res = "正常"
        if mar>0.5: res="大笑"
        elif mjr>0.45: res="微笑"
        mouthHull = cv2.convexHull(shape[48:61])
        frame = cv2AddChineseText(frame, res, mouthHull[0,0], (0,255,255), 25)
        cv2.drawContours(frame, [mouthHull], -1, (0,255,0), 1)
        
        # 疲劳检测
        re, le = shape[36:42], shape[42:48]
        ear = (eye_aspect_ratio(re)+eye_aspect_ratio(le))/2
        if ear < 0.28:
            COUNTER +=1
            if COUNTER>=40:
                frame = cv2AddChineseText(frame, "!!!!!危险!!!!! ", (200,200), (0,0,255), 60)
        else:
            COUNTER=0
            drawEye(re, frame)
            drawEye(le, frame)
            frame = cv2AddChineseText(frame, f"EAR:{ear[0][0]:.2f}", (10,10), (255,0,0), 25)
    
    # 年龄性别预测
    for box in boxes:
        x1,y1,x2,y2 = box
        face = frame[y1:y2, x1:x2]
        blob = cv2.dnn.blobFromImage(face,1.0,(227,227),mean)
        gender = genderList[genderNet.forward(blob).argmax()]
        age = ageList[ageNet.forward(blob).argmax()]
        frame = cv2AddChineseText(frame, f"{gender},{age}", (x1,y1-30))
    
    cv2.imshow('人脸智能分析系统', frame)
    if cv2.waitKey(1)==27: break

cap.release()
cv2.destroyAllWindows()

四、系统效果与优化方向

1. 运行效果

  1. 实时性:视频流流畅运行,无明显卡顿;
  2. 疲劳检测:持续闭眼自动触发红色警报,睁眼恢复正常;
  3. 表情识别:精准识别微笑 / 大笑,黄色文字实时显示;
  4. 属性预测:人脸框上方显示性别和年龄,绿色框标注人脸区域;
  5. 可视化:眼睛、嘴巴绘制绿色轮廓,EAR 数值实时显示。

五、总结

本文基于计算机视觉开源技术栈,完整实现了一套多功能人脸智能分析系统,涵盖了疲劳驾驶检测、面部表情识别、年龄性别预测三大核心功能。我们从环境搭建、原理讲解、分模块实现到一体化融合,全方位展示了人脸视觉分析的开发流程。

该系统不仅适用于驾驶安全监测场景,还可拓展到智能门禁人机交互短视频美颜课堂专注度监测等多个领域。通过本文的学习,你可以掌握 Dlib 关键点定位、EAR/MAR 几何特征计算、OpenCV DNN 深度学习推理等核心技能,为后续深入研究计算机视觉打下坚实基础。

计算机视觉技术的落地应用,核心在于算法原理 + 工程实践的结合。希望本文能帮助更多开发者入门人脸智能分析,用技术创造更多实用、有趣的应用!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐