OpenCV+Dlib实战:人脸检测 + 表情识别 + 年龄性别预测

一、前言

在计算机视觉入门项目中,人脸相关应用最容易上手、效果也最直观。本文基于 OpenCV + Dlib,分三部分实现:

  1. 实时表情识别(正常 / 微笑 / 大笑)
  2. 高精度人脸检测(Dlib CNN 检测器)
  3. 年龄与性别实时预测(OpenCV DNN 预训练模型)

二、环境配置

python 复制代码
pip install opencv-python numpy dlib pillow scikit-learn

模块一:基于 Dlib 关键点的实时表情识别

1. 实现思路

  • 使用 Dlib 68 点人脸关键点定位
  • 提取嘴部区域关键点
  • 计算两个比值:
    • MAR:嘴巴宽高比 → 判断是否大笑
    • MJR:嘴宽 / 脸颊宽 → 判断是否微笑
  • 绘制嘴部轮廓 + 实时显示表情结果
  • 解决 OpenCV 中文乱码问题

2. 完整代码

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

# 计算嘴的宽高比 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

# 计算嘴宽度 / 脸颊宽度比值 MJR
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

# OpenCV 显示中文
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()
    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 = "正常"
        
        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()

3. 效果说明

  • 正常:无明显表情
  • 微笑:嘴角轻微上扬
  • 大笑:嘴巴明显张开
  • 实时绘制嘴部轮廓,支持多人脸

模块二:Dlib CNN 高精度人脸检测

1. 实现思路

  • 使用 Dlib 官方 CNN 人脸检测器:mmod_human_face_detector.dat
  • 对图片进行人脸检测
  • 绘制人脸矩形框
  • 适合复杂场景、侧脸、遮挡场景检测

2. 完整代码

python 复制代码
import dlib
import cv2

# 加载 CNN 人脸检测器
cnn_face_detector = dlib.cnn_face_detection_model_v1("mmod_human_face_detector.dat")

# 读取图片
img = cv2.imread("people1.png")

# 检测人脸
faces = cnn_face_detector(img, 0)

# 遍历绘制框
for d in faces:
    rect = d.rect
    left = rect.left()
    top = rect.top()
    right = rect.right()
    bottom = rect.bottom()
    cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3)

cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

3. 特点

  • 比传统 HOG 检测器更准
  • 对遮挡、小角度人脸更鲁棒
  • 适合静态图片高精度检测

模块三:基于 OpenCV DNN 的年龄与性别实时预测

1. 实现思路

  • 使用 OpenCV DNN 加载 Caffe 预训练模型
  • 先检测人脸区域
  • 对人脸区域分别预测性别与年龄
  • 实时在画面上标注中文结果
  • 支持摄像头实时检测

2. 完整代码

python 复制代码
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-6岁', '8-12岁', '15-20岁', '25-32岁', '38-43岁', '48-53岁', '60-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=(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)

# 打开摄像头
cap = cv2.VideoCapture(0)

while True:
    _, frame = cap.read()
    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 = "{},{}".format(gender, age)
        frame = cv2AddChineseText(frame, result, (x1, y1 - 30))

    cv2.imshow("result", frame)
    if cv2.waitKey(1) == 27:
        break

cv2.destroyAllWindows()
cap.release()

3. 效果说明

  • 实时框选人脸
  • 显示:男性 / 女性 + 年龄段
  • 支持多人脸、实时摄像头
  • 中文清晰不乱码

三、项目总结

本文分三大模块完整实现:

  1. 表情识别:基于 68 关键点,判断正常、微笑、大笑
  2. 人脸检测:Dlib CNN 高精度检测,适合复杂场景
  3. 年龄性别预测:OpenCV DNN 预训练模型,实时预测
相关推荐
Martina_03212 分钟前
AI生成的过山车轨道导入后频繁脱轨?用5步检查样条、轨距与碰撞
图像处理·人工智能·游戏·3d·材质·游戏策划·关卡设计
小猴子爱上树7 分钟前
跨马翻译:批量图片翻译+视频字幕+智能抠图,跨境电商在线图片翻译工具
大数据·人工智能·python·音视频
佳瑞Jarrett7 分钟前
从 0 到 1 手搓 AI 调解训练系统:双 NPC 实时语音 + AI 自动评分(FastAPI + Qwen-Audio Realtime 实战)
人工智能
W***25927 分钟前
2026 企业 AI 办公工具怎么选:选型框架与平台全景分析
大数据·人工智能
薛定e的猫咪10 分钟前
(AISTATS 2023)BaCaDI 逐章阅读
人工智能·深度学习·算法·机器学习
记得开心一点嘛14 分钟前
Trellora:基于 Electron、React 和本地知识库的 AI 知识工作台
人工智能·react.js·electron
桃西西呀21 分钟前
LangChain 之八:流式与透传
人工智能·langchain·llm
凡达Ai派24 分钟前
AI画布里的文字总是错位或乱码?把生成、排版和校对拆成三段
图像处理·人工智能·深度学习·神经网络·自然语言处理·知识图谱
桃西西呀27 分钟前
LangChain 之九:一个能检索又会调工具的流式问答助手
人工智能·langchain·llm
Martina_032132 分钟前
AI生成的模块场景一烘焙就有黑边?用6步检查Lightmap UV、纹素密度与Padding
人工智能·游戏·3d·aigc·uv·游戏策划·关卡设计