一、引言
在计算机视觉领域,人脸分析是一个热门且应用广泛的研究方向。其中,人脸性别年龄检测能够自动识别图像或视频流中人脸的性别和年龄信息,具有诸多实际应用场景,如市场调研、安防监控、用户个性化体验等。OpenCV 作为一个强大的计算机视觉库,提供了丰富的工具和预训练模型来实现这一功能。
二、原理概述
人脸检测:首先需要在输入的图像或视频帧中检测出人脸。OpenCV 常用的人脸检测方法基于 Haar 级联检测器或基于深度学习的目标检测算法(如 SSD、YOLO 等)。Haar 级联检测器通过构建一系列简单的 Haar 特征,并利用 AdaBoost 算法训练出一个强分类器来识别图像中的人脸区域。基于深度学习的方法则通过在大规模人脸数据集上训练卷积神经网络(CNN),学习人脸的特征模式,从而实现更准确的人脸检测。
性别年龄预测:一旦检测到人脸,将人脸区域进行预处理(如裁剪、归一化等)后输入到预训练的性别年龄预测模型中。这些模型通常也是基于深度学习的 CNN 架构。在训练过程中,模型学习到不同年龄和性别人脸的特征表示,通过对输入人脸图像的特征提取和分析,预测出该人脸对应的性别(通常为男性或女性)和年龄范围(如儿童、青少年、成年人、老年人等)。
pip install opencv - python
下载预训练模型:
人脸检测模型:对于 Haar 级联人脸检测,可以从 OpenCV 官方的 GitHub 仓库下载haarcascade_frontalface_default.xml文件。该文件包含了训练好的 Haar 级联分类器参数。
性别年龄预测模型:性别年龄预测模型通常基于深度学习,如 Caffe 模型。可以从相关开源项目中下载预训练的deploy_gender.prototxt和gender_net.caffemodel文件用于性别预测,以及deploy_age.prototxt和age_net.caffemodel文件用于年龄预测。这些模型在大规模人脸数据集上进行了训练,具有一定的准确性。
准备输入数据:准备用于检测的图像或视频文件。确保图像或视频中的人脸清晰可见,光线条件良好,以提高检测的准确性。
三、代码实现
1.导入必要的库
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as np
导入cv2库用于计算机视觉处理,PIL库中的Image、ImageDraw、ImageFont用于在图像上绘制中文字符,numpy库用于数值计算。
2.加载模型文件路径
获取路径:通过网盘分享的文件:model2
链接: https://pan.baidu.com/s/1gS-5xqOexYyMQ_wUQJTR0w 提取码: ued3
faceProto = "model2/opencv_face_detector.pbtxt"
faceModel = "model2/opencv_face_detector_uint8.pb"
ageProto = "model2/deploy_age.prototxt"
ageModel = "model2/age_net.caffemodel"
genderProto = "model2/deploy_gender.prototxt"
genderModel = "model2/gender_net.caffemodel"
定义人脸检测、年龄预测和性别预测模型的配置文件(.pbtxt或.prototxt)和权重文件(.pb或.caffemodel)的路径。
3.读取模型
ageNet = cv2.dnn.readNet(ageModel, ageProto)
genderNet = cv2.dnn.readNet(genderModel, genderProto)
faceNet = cv2.dnn.readNet(faceModel, faceProto)
使用cv2.dnn.readNet函数读取年龄、性别和人脸检测模型,以便后续用于推理
4.定义年龄和性别标签列表及均值
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)
创建年龄和性别标签列表,用于将模型预测的类别索引转换为实际的年龄范围和性别描述。同时定义了图像归一化所需的均值。
5.人脸检测函数
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
这个函数接受一个模型net和一个视频帧frame作为输入。首先获取帧的高度和宽度,然后使用cv2.dnn.blobFromImage将帧转换为适合模型输入的 blob 格式,设置模型输入并进行前向推理得到检测结果。遍历检测结果,筛选出置信度大于 0.7 的检测框,将其坐标转换为实际图像中的坐标并添加到faceBoxes列表中,同时在原帧上绘制检测框。最后返回绘制了检测框的帧和检测框坐标列表。
6.在图像上绘制中文字符的函数
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("simhei.ttf", textSize, encoding="utf-8")draw.text(position, text, textColor, font=fontStyle)return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
该函数用于在图像上绘制中文字符。首先判断输入的图像是否为 OpenCV 的numpy.ndarray格式,如果是则将其转换为PIL的Image格式。然后使用ImageDraw和ImageFont设置字体样式并在图像上指定位置绘制文本,最后再将图像转换回 OpenCV 的BGR格式并返回
7.主循环
cap = cv2.VideoCapture(0)
while True:_, frame = cap.read()frame = cv2.flip(frame, 1)frame, faceBoxes = getBoxes(faceNet, frame)if not faceBoxes:print("当前镜头中没有人")continuefor faceBox in faceBoxes:x1, y1, x2, y2 = faceBoxface = frame[y1:y2, x1: x2]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()]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()
初始化摄像头设备,通过cv2.VideoCapture(0)打开默认摄像头。进入无限循环,不断读取摄像头的帧,使用cv2.flip对帧进行水平翻转(以实现镜像效果)。调用getBoxes函数进行人脸检测,获取绘制了检测框的帧和检测到的人脸框列表。如果没有检测到人脸,则打印提示信息并继续下一次循环。对于检测到的每一张人脸,提取人脸区域,将其转换为适合性别和年龄模型输入的 blob 格式,分别输入到性别和年龄预测模型中进行推理,获取预测结果并从标签列表中找到对应的性别和年龄描述,将两者组合成结果字符串,使用cv2AddchineseText函数在图像上绘制结果。最后使用cv2.imshow显示处理后的帧,当用户按下Esc键(键值为 27)时,退出循环。循环结束后,释放摄像头资源并关闭所有 OpenCV 窗口。
完整代码:
import cv2
from PIL import Image, ImageDraw, ImageFont
import numpy as npfaceProto = "model2/opencv_face_detector.pbtxt"
faceModel = "model2/opencv_face_detector_uint8.pb"
ageProto = "model2/deploy_age.prototxt"
ageModel = "model2/age_net.caffemodel"
genderProto = "model2/deploy_gender.prototxt"
genderModel = "model2/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, faceBoxesdef cv2AddchineseText(img, text, position, textColor=(0, 255, 0), textSize=30):if isinstance(img, np.ndarray): # 判断是否为OpenCV图片类型img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img)fontStyle = ImageFont.truetype("simhei.ttf", 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("当前镜头中没有人")continuefor faceBox in faceBoxes:x1, y1, x2, y2 = faceBoxface = frame[y1:y2, x1: x2]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()]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()
最后实现对人脸性别年龄的检测
四、总结
通过 OpenCV,我们可以方便地实现人脸性别年龄检测。利用其提供的预训练模型和丰富的函数接口,结合简单的代码编写,就能够搭建起一个实用的人脸分析系统。希望本文能帮助你快速上手并在实际项目中应用这一技术