基于 OpenCV DNN 的实时人脸检测与年龄、性别识别系统全解析(含完整源码)
一、项目概述
在计算机视觉领域中,人脸检测 与**人脸属性识别(如年龄、性别)**是最典型的视觉分析任务之一。本文将带你从零构建一个完整的"摄像头实时人脸检测 + 年龄识别 + 性别识别"系统,基于 OpenCV 的 DNN 模块和预训练的 Caffe 模型实现。
系统功能:
-
自动检测摄像头中的人脸;
-
实时预测每张人脸的年龄段与性别;
-
中文可视化输出;
-
结构清晰、易于扩展(可添加情绪识别、人脸识别等模块)。
二、完整源码
以下是完整的 Python 实现代码,包含详细注释,直接可运行。
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np
# =====模型初始化========
# 模型(网络模型/预训练模型):face/age/gender(脸、年龄、性别)
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), int(round(frameHeight / 150)), 6)
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[max(0, y1):min(y2, frame.shape[0]),
max(0, x1):min(x2, frame.shape[1])]
blob = cv2.dnn.blobFromImage(face, 1.0, (227, 227), mean)
# 性别预测
genderNet.setInput(blob)
genderOuts = genderNet.forward()
gender = genderList[genderOuts[0].argmax()]
# 年龄预测
ageNet.setInput(blob)
ageOuts = ageNet.forward()
age = ageList[ageOuts[0].argmax()]
label = "{}, {}".format(gender, age)
frame = cv2AddChineseText(frame, label, (x1, y1 - 30))
cv2.imshow("result", frame)
if cv2.waitKey(1) == 27: # 按ESC退出
break
cap.release()
cv2.destroyAllWindows()
三、逐段解析与原理讲解
1️⃣ 模型加载
cv2.dnn.readNet()
可加载多种模型格式(Caffe、TensorFlow、ONNX 等)。
DNN 模块是 OpenCV 的轻量推理引擎,可以在 CPU 上直接运行深度学习模型,无需 TensorFlow/PyTorch 环境,非常适合嵌入式或教学场景。
2️⃣ blobFromImage 的意义
cv2.dnn.blobFromImage()
是预处理函数,主要步骤:
-
调整输入大小(如 227×227)
-
减去每个通道的均值(mean)
-
转换通道顺序(BGR→RGB)
-
生成四维输入张量
[batch, channels, height, width]
这确保输入图像的格式与模型训练时一致,否则输出会失真。
3️⃣ 人脸检测模块
opencv_face_detector_uint8.pb
模型基于 SSD(Single Shot MultiBox Detector)网络结构。
输出 detections
的形状为 [1, 1, N, 7]
,每个检测包含:
[image_id, class_id, confidence, x1, y1, x2, y2]
当置信度大于 0.7 时,才认为检测到人脸。
4️⃣ 中文绘制函数
OpenCV 自带的 cv2.putText()
不支持中文,需借助 Pillow:
-
把 OpenCV 图像转为 Pillow Image;
-
用
ImageDraw
绘制文字; -
再转回 OpenCV 格式。
字体文件 simsun.ttc
在 Windows 系统中路径为:
C:\Windows\Fonts\simsun.ttc
如在 Linux / macOS,需要指定可用中文字体路径。
5️⃣ 年龄与性别预测
输入到 ageNet
与 genderNet
的数据都是 blob,经前向传播 forward()
输出各类别概率。
年龄模型输出 8 个概率,对应八个年龄段:
['0-2', '4-6', '8-12', '15-20', '25-32', '38-43', '48-53', '60-100']
性别模型输出 2 个概率:['Male', 'Female']
。
我们取最大概率对应类别的索引,匹配列表即得预测结果。
四、运行效果与测试说明
运行程序后,摄像头开启:
-
检测到人脸会显示绿色矩形框;
-
框上方标注中文"性别, 年龄段";
-
没有人脸时会在控制台输出"当前镜头中没有人"。
按下 ESC 即可退出。
测试环境建议:
-
光线充足;
-
人脸正对摄像头;
-
距离 0.5--1 米范围;
-
分辨率建议 640×480 或 720p。
五、常见问题与解决方案
问题 | 原因 | 解决方法 |
---|---|---|
报错找不到模型文件 | 路径错误或模型未下载 | 确保路径与脚本一致 |
中文乱码 | 字体文件缺失 | 使用系统字体或改用英文 |
摄像头打不开 | 设备占用或索引错误 | 改用 cv2.VideoCapture(1) |
性别识别不准 | 输入未裁剪人脸 | 使用裁剪后的人脸区域 |
延迟高 | 模型较大 | 使用 GPU 或 OpenVINO 加速 |
六、性能优化建议
-
模型加速:
faceNet.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) faceNet.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA_FP16)
在支持 CUDA 的系统上显著加速。
-
多线程采集:
视频采集线程与推理线程分离,可防止阻塞。
-
帧率控制:
若实时性要求不高,可每隔 5 帧进行一次推理。
-
轻量模型替换:
可用 MobileNet 或 ONNX 模型取代 Caffe 模型以提升速度。
七、伦理与隐私声明
-
隐私保护:本系统仅作技术演示,请勿将人脸数据用于未经授权的采集或识别。
-
偏差问题:模型在不同种族、光照、角度下可能产生偏差,不适用于安全或法律决策。
-
数据安全:在生产系统中应遵守《个人信息保护法》等相关法规,明确用途与存储策略。
八、结语与扩展方向
本文展示了如何用简洁的 Python 代码构建一个完整的"人脸检测 + 年龄/性别识别"系统。整个流程使用 OpenCV 的 DNN 模块,无需额外深度学习框架即可实现。
扩展方向包括:
-
加入 人脸表情识别;
-
添加 人脸关键点定位 提升检测精度;
-
将系统部署到 Flask Web 服务 或 移动端;
-
利用 ONNX Runtime / TensorRT 实现高性能推理。
通过对该项目的理解,你不仅能掌握人脸属性识别的流程,也能深入理解深度学习模型在视觉任务中的应用方式。