Logo
Section 1 / 6

年龄预测

让我们学习如何从人脸图像中预测年龄。

导入

年龄预测

让我们学习如何从人脸图像中预测年龄。

简介

年龄是人类的基本特征之一。年龄估计通常基于从面部外观中提取的不同模式。近年来,年龄估计已成为多个现实应用场景中的关键属性,例如:

  • 访问控制与视觉监控。
  • 人机交互(HCI)。
  • 市场智能,例如,AI产品Quividi能够实现面向人脸和场景的广告投放。

然而,从面部图像中准确估计年龄仍然具有挑战性,因为它可能受到多种因素的影响,包括光照变化、尺度差异、遮挡情况,以及个体间(尤其是青少年和年轻人)在年龄表现上的差异。

近年来,许多基于卷积神经网络(CNN)模型的机器学习算法被广泛应用于自动年龄估计与分类任务中,显著提升了该领域的效率和准确性。CNN本质上是一种深度学习算法,它能够接收输入图像,并为图像中的不同区域或对象分配重要性(即可学习的权重和偏置),从而实现区分。

目标

在本课程中,我们将利用先进的Python库 DeepFace,通过人脸图像进行年龄估计。

面部年龄估计流程主要包括两个关键步骤:

  1. 在输入图像中检测并定位人脸。

  2. 对定位到的人脸区域应用年龄预测模型,该区域被视为感兴趣区域(ROI, Region of Interest),模型将据此预测人物的年龄。

依赖项

我们需要以下外部Python库:

库版本
Deepface0.0.68
MediaPipe0.8.9
opencv-python4.4.0.46
filetype1.0.7

编写核心函数

本工具的核心功能如下:

enlarge_bounding_box 函数

该函数用于将围绕图像区域(如人脸区域)的边界框按预设百分比扩大,具体操作包括:

  • 第6—9行:根据扩展因子参数 EXPANDING_FACTOR 计算新的坐标值。

  • 第10—11行:确保计算出的坐标值不为负数。

  • 第12行:输出计算得到的新坐标。

完整代码如下:

1def enlarge_bounding_box(x, y, w, h): 2 """ 3 根据扩展因子放大边界框 4 """ 5 # 创建一个包含缓冲区的更大边界框 6 x1 = int(x - EXPANDING_FACTOR * w) 7 w1 = int(w + 2 * EXPANDING_FACTOR * w) 8 y1 = int(y - EXPANDING_FACTOR * h) 9 h1 = int(h + 2 * EXPANDING_FACTOR * h) 10 x1 = 0 if x1 < 0 else x1 11 y1 = 0 if y1 < 0 else y1 12 print('x1,y1,w1,h1', x1, y1, w1, h1) 13 return x1,y1,w1,h1

predict_age_deepface 函数

这是本工具的核心函数,用于从人脸图像中自动预测年龄,其主要步骤如下:

  • 第6行:初始化 MediaPipe 的人脸检测子模块。

  • 第9行:使用 OpenCV 库读取图像。

  • 第12行:保留原始图像的一份副本用于后续处理。

  • 第15行:将图像从BGR格式转换为RGB格式。需注意,OpenCV 默认以BGR格式加载图像。

  • 第18行:使用 MediaPipe 的人脸检测模块处理转换后的RGB图像。

  • 第24–25行:输出检测到的人脸数量信息。

  • 第28行:遍历所有检测到的人脸,并对每张人脸执行后续操作。

  • 第31–32行:输出每张检测人脸的标识符及其检测得分。

  • 第35–40行:确定检测到的人脸的相对边界框位置。

  • 第43行:获取人脸边界框的实际坐标。

  • 第46行:使用预定义的 EXPANDING_FACTOR 参数(表示边界框扩展比例)扩大人脸区域,以获得更佳分析效果。

  • 第49行:裁剪出扩大的人脸区域。

  • 第53行:使用 DeepFace 库对裁剪后的人脸图像进行分析。

  • 第65–77行:若成功估计年龄,则在人脸下方绘制一个填充矩形,并显示预测年龄。

  • 第84行:若无法预测年龄,则在人脸周围绘制红色矩形框。

  • 第97–104行:输出处理后的图像结果。

完整代码如下:

1def predict_age_deepface(input_path:str,display_output:bool = False): 2 """ 3 预测人脸图像的年龄 4 """ 5 # 初始化 mediapipe 人脸检测子模块 6 mpFaceDetection = initialize_mediapipe() 7 8 # 读取输入图像 9 img = cv2.imread(input_path) 10 11 # 保留原始图像副本 12 frame = img.copy() 13 14 # 将图像从 BGR 转换为 RGB 格式 15 rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 16 17 # 使用 RGB 图像进行人脸检测 18 faces = mpFaceDetection.process(rgb_frame) 19 20 output = [] 21 output_info = [] 22 23 # 输出检测到的人脸数量信息 24 output_msg = {'msg':"{} 张人脸被检测到。".format(len(faces.detections)),'category':"info"} 25 output_info.append(output_msg) 26 27 # 遍历检测到的每个人脸 28 for idx, face_detected in enumerate(faces.detections): 29 30 output_item = None 31 label = f"人脸 ID = {(idx+1)} - 检测得分 {int(face_detected.score[0]*100)}%" 32 print(label) 33 34 # 获取相对边界框 35 relativeBoundingBox = face_detected.location_data.relative_bounding_box 36 frameHeight,frameWidth,frameChannels = frame.shape 37 faceBoundingBox = int(relativeBoundingBox.xmin*frameWidth) \ 38 ,int(relativeBoundingBox.ymin*frameHeight) \ 39 ,int(relativeBoundingBox.width*frameWidth) \ 40 ,int(relativeBoundingBox.height*frameHeight) 41 42 # 获取人脸边界框坐标 43 x, y, w, h = faceBoundingBox 44 45 # 扩大边界框以包含更多上下文信息 46 x1, y1, w1, h1 = enlarge_bounding_box(x, y, w, h) 47 48 # 裁剪出扩大的人脸区域用于分析 49 roi_face_color = frame[y1:y1+h1,x1:x1+w1] 50 51 try: 52 # 使用 DeepFace 分析裁剪后的人脸 53 result = DeepFace.analyze(np.array(roi_face_color), actions=['age']) 54 print('### DeepFace.analyze 结果 = ',result) 55 56 if result['age']: 57 # 绘制绿色边框 58 label = "AGE {}".format(result['age']) 59 print(label) 60 61 # 计算标签文字的最佳字体缩放比例 62 optimal_font_scale = calculate_optimal_fontscale(label, (((x + w) - x) )) 63 64 # 绘制标签 65 optimal_font_scale = 1 if optimal_font_scale < 1 else optimal_font_scale 66 cv2.rectangle(frame, (x,y), (x+w,y+h), (0, 255, 0), 2 * round(optimal_font_scale)) 67 labelSize = cv2.getTextSize(label,cv2.FONT_HERSHEY_DUPLEX,round(optimal_font_scale),2) 68 _x1 = x 69 _y1 = y+h 70 _x2 = _x1 + labelSize[0][0] 71 _y2 = _y1 + int(labelSize[0][1]) 72 cv2.rectangle(frame, (_x1, _y1), (_x2,_y2), (0, 255, 0), cv2.FILLED) 73 cv2.putText(frame, label ,(_x1,_y2) 74 , cv2.FONT_HERSHEY_DUPLEX 75 , int(optimal_font_scale) 76 , (0, 0, 0) 77 , 2) 78 else: 79 # 若未预测出年龄,绘制红色边框 80 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2) 81 except Exception as err: 82 print('发现异常',Exception,err) 83 # 发生异常时,用红色框标记人脸 84 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0,255), 2) 85 86 if display_output: 87 # 在屏幕上显示图像 88 label = "使用 DeepFace 进行年龄估计" 89 cv2.imshow(label,frame) 90 # 持续显示直到用户按键 91 cv2.waitKey(0) 92 93 if display_output: 94 # 清理窗口 95 cv2.destroyAllWindows() 96 97 # 保存处理后的图像 98 output_filepath = os.path.join(config.PROCESSED_PATH 99 ,str(uuid.uuid4().hex) + os.path.splitext(input_path)[1]) 100 cv2.imwrite(output_filepath,frame) 101 102 output_item = {'id': 1, 'folder': config.PROCESSED_FOLDER 103 , 'name': os.path.basename(output_filepath) 104 , 'msg': os.path.basename(output_filepath)} 105 output.append(output_item) 106 mpFaceDetection.close() 107 return output_info , output

测试场景

我们来估计一张数字图像中多个人脸的年龄。

对于练习,可以尝试修改上述代码,开发自定义测试用例。

结论

尽管近年来年龄预测的准确性已有显著提升,但该过程仍充满挑战且存在不确定性。因此,必须明确:预测出的年龄仅为实际年龄的估算值。

核心函数

性别预测