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 预训练模型,实时预测
相关推荐
ModelWhale2 小时前
从“社区”到“生态”:和鲸科技CEO范向伟在InnovateX大赛揭示OPC孵化“正确路径”
大数据·人工智能·科技
Binary_ey2 小时前
车载 AR-HUD 虚像不清晰?OAS软件跨尺度仿真来助力
人工智能·ar·软件需求·光学设计·光学软件
博.闻广见2 小时前
AI_线性代数-1.矩阵
人工智能·线性代数·矩阵
xiaoduo AI2 小时前
客服机器人知识库多久更新一次?智能 Agent 自动爬取新问答,过期话术能否及时淘汰?
大数据·人工智能·机器人
好运的阿财2 小时前
OpenClaw工具拆解之 sessions_list+sessions_history
人工智能·python·程序人生·ai·ai编程·openclaw
Westward-sun.2 小时前
OpenCV 疲劳检测实战:用 dlib 计算眼睛纵横比 (EAR)
人工智能·opencv·计算机视觉·视觉检测
AI周红伟2 小时前
Hermes Agent 工具-周红伟
linux·网络·人工智能·腾讯云·openclaw
杜子不疼.2 小时前
Python + AI 实战:用 LangChain 搭建企业级 RAG 知识库
人工智能·python·langchain
阿杰学AI2 小时前
AI核心知识118—大语言模型之 Software 2.0 (简洁且通俗易懂版)
人工智能·ai·语言模型·自然语言处理·aigc·编程·software 2.0