如何在Python中使用OpenCV进行年龄检测?

2021年11月11日02:01:09 发表评论 596 次浏览

了解如何使用 Python 中的 OpenCV 库从某人的正面图片中预测其年龄,包括完整的OpenCV检测年龄示例

最近,计算机视觉领域受到广泛关注,尤其是在人脸识别、检测和人脸地标定位方面。许多重要特征可以直接从人脸中衍生出来,例如年龄、性别和情绪。

OpenCV年龄检测:年龄估计可以定义为将面部图像分类为确切年龄或特定年龄范围的自动过程。基本上,从面部估计年龄仍然是一个具有挑战性的问题,由于化妆、灯光、障碍物和面部表情等因素,从单个图像中猜测确切年龄非常困难。

受 Android 上的“AgeBot”、iPhone 上的“年龄计算器”等跨多个渠道的许多无处不在的应用程序的启发,我们将使用Python 中的OpenCV构建一个简单的年龄估计器。 

本教程的主要目标是通过基于 Python 的模块开发一个基于命令行的轻量级实用程序,旨在描述在静态图像中自动检测人脸并使用基于深度学习的年龄检测模型。

请注意,如果你想同时检测年龄和性别,请查看本教程。

还学习: 在 Python 中使用 OpenCV 进行性别检测。

OpenCV如何检测年龄?以下组件发挥作用:

  • OpenCV:是一个用于计算机视觉、机器学习和图像处理的开源库。OpenCV 支持 Python、C++、Java 等多种编程语言,可用于各种图像和视频分析,如面部检测和识别、照片编辑、光学字符识别等等。使用 OpenCV 有很多好处,其中包括:
    • OpenCV 是一个开源库,它是免费的。
    • OpenCV 速度很快,因为它是用 C/C++ 编写的。
    • OpenCV 支持大多数操作系统,例如 Windows、Linux 和 macOS。
      建议:查看我们的计算机视觉教程,了解更多 OpenCV 用例。
  • filetype:是一个小型且无依赖的 Python 包,用于推断文件和 MIME 类型。

OpenCV检测年龄示例:出于本文的目的,我们将使用预训练的 Caffe 模型,一个来自人脸检测教程的人脸检测模型,另一个用于年龄检测的模型。以下是包含在我们的项目目录中的必要文​​件列表:

  • age_net.caffemodel:这是用于年龄检测的预训练模型权重。你可以在这里下载。
  • deploy_age.prototxt: 是年龄检测模型的模型架构(一个带有类似 JSON 结构的纯文本文件,包含所有神经网络层的定义)。从这里获取。
  • res10_300x300_ssd_iter_140000_fp16.caffemodel:用于人脸检测的预训练模型权重,请在此处下载。
  • deploy.prototxt.txt:这是人脸检测模型的模型架构,在这里下载。

下载 4 个必需的文件后,将它们放在一个文件夹中并命名为“权重”:

如何在Python中使用OpenCV进行年龄检测?

首先,让我们安装 OpenCV 和 NumPy:

$ pip install opencv-python numpy

打开一个新的 Python 文件:

# Import Libraries
import cv2
import os
import filetype
import numpy as np

# The model architecture
# download from: https://drive.google.com/open?id=1kiusFljZc9QfcIYdU2s7xrtWHTraHwmW
AGE_MODEL = 'weights/deploy_age.prototxt'
# The model pre-trained weights
# download from: https://drive.google.com/open?id=1kWv0AjxGSN0g31OeJa02eBGM0R_jcjIl
AGE_PROTO = 'weights/age_net.caffemodel'
# Each Caffe Model impose the shape of the input image also image preprocessing is required like mean
# substraction to eliminate the effect of illunination changes
MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)
# Represent the 8 age classes of this CNN probability layer
AGE_INTERVALS = ['(0, 2)', '(4, 6)', '(8, 12)', '(15, 20)',
                 '(25, 32)', '(38, 43)', '(48, 53)', '(60, 100)']
# download from: https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt
FACE_PROTO = "weights/deploy.prototxt.txt"
# download from: https://raw.githubusercontent.com/opencv/opencv_3rdparty/dnn_samples_face_detector_20180205_fp16/res10_300x300_ssd_iter_140000_fp16.caffemodel
FACE_MODEL = "weights/res10_300x300_ssd_iter_140000_fp16.caffemodel"
# Initialize frame size
frame_width = 1280
frame_height = 720
# load face Caffe model
face_net = cv2.dnn.readNetFromCaffe(FACE_PROTO, FACE_MODEL)
# Load age prediction model
age_net = cv2.dnn.readNetFromCaffe(AGE_MODEL, AGE_PROTO)

OpenCV年龄检测示例 - 在这里,我们初始化了模型权重和架构的路径,我们要调整到的图像大小,最后加载模型。

变量AGE_INTERVALS是年龄检测模型的年龄类别列表。

OpenCV如何检测年龄?接下来,让我们创建一个函数,将图像作为输入,并返回检测到的人脸列表:

def get_faces(frame, confidence_threshold=0.5):
    """Returns the box coordinates of all detected faces"""
    # convert the frame into a blob to be ready for NN input
    blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104, 177.0, 123.0))
    # set the image as input to the NN
    face_net.setInput(blob)
    # perform inference and get predictions
    output = np.squeeze(face_net.forward())
    # initialize the result list
    faces = []
    # Loop over the faces detected
    for i in range(output.shape[0]):
        confidence = output[i, 2]
        if confidence > confidence_threshold:
            box = output[i, 3:7] * np.array([frame_width, frame_height, frame_width, frame_height])
            # convert to integers
            start_x, start_y, end_x, end_y = box.astype(np.int)
            # widen the box a little
            start_x, start_y, end_x, end_y = start_x - \
                10, start_y - 10, end_x + 10, end_y + 10
            start_x = 0 if start_x < 0 else start_x
            start_y = 0 if start_y < 0 else start_y
            end_x = 0 if end_x < 0 else end_x
            end_y = 0 if end_y < 0 else end_y
            # append to our list
            faces.append((start_x, start_y, end_x, end_y))
    return faces

大多数代码是从人脸检测教程中获取的,查看它以获取有关如何完成的更多信息。

让我们创建一个显示给定图像的实用函数:

def display_img(title, img):
    """Displays an image on screen and maintains the output until the user presses a key"""
    # Display Image on screen
    cv2.imshow(title, img)
    # Mantain output until user presses a key
    cv2.waitKey(0)
    # Destroy windows when user presses a key
    cv2.destroyAllWindows()

接下来,下面是两个实用函数,一个用于在将文本打印到图像时找到合适的字体大小,另一个用于动态调整图像大小:

def get_optimal_font_scale(text, width):
    """Determine the optimal font scale based on the hosting frame width"""
    for scale in reversed(range(0, 60, 1)):
        textSize = cv2.getTextSize(text, fontFace=cv2.FONT_HERSHEY_DUPLEX, fontScale=scale/10, thickness=1)
        new_width = textSize[0][0]
        if (new_width <= width):
            return scale/10
    return 1

# from: https://stackoverflow.com/questions/44650888/resize-an-image-without-distortion-opencv
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
    # initialize the dimensions of the image to be resized and
    # grab the image size
    dim = None
    (h, w) = image.shape[:2]
    # if both the width and height are None, then return the
    # original image
    if width is None and height is None:
        return image
    # check to see if the width is None
    if width is None:
        # calculate the ratio of the height and construct the
        # dimensions
        r = height / float(h)
        dim = (int(w * r), height)
    # otherwise, the height is None
    else:
        # calculate the ratio of the width and construct the
        # dimensions
        r = width / float(w)
        dim = (width, int(h * r))
    # resize the image
    return cv2.resize(image, dim, interpolation = inter)

OpenCV检测年龄示例 - 现在我们知道如何检测人脸了,下面的函数负责为检测到的每个人脸预测年龄:

def predict_age(input_path: str):
    """Predict the age of the faces showing in the image"""
    # Read Input Image
    img = cv2.imread(input_path)
    # Take a copy of the initial image and resize it
    frame = img.copy()
    if frame.shape[1] > frame_width:
        frame = image_resize(frame, width=frame_width)
    faces = get_faces(frame)
    for i, (start_x, start_y, end_x, end_y) in enumerate(faces):
        face_img = frame[start_y: end_y, start_x: end_x]
        # image --> Input image to preprocess before passing it through our dnn for classification.
        blob = cv2.dnn.blobFromImage(
            image=face_img, scalefactor=1.0, size=(227, 227), 
            mean=MODEL_MEAN_VALUES, swapRB=False
        )
        # Predict Age
        age_net.setInput(blob)
        age_preds = age_net.forward()
        print("="*30, f"Face {i+1} Prediction Probabilities", "="*30)
        for i in range(age_preds[0].shape[0]):
            print(f"{AGE_INTERVALS[i]}: {age_preds[0, i]*100:.2f}%")
        i = age_preds[0].argmax()
        age = AGE_INTERVALS[i]
        age_confidence_score = age_preds[0][i]
        # Draw the box
        label = f"Age:{age} - {age_confidence_score*100:.2f}%"
        print(label)
        # get the position where to put the text
        yPos = start_y - 15
        while yPos < 15:
            yPos += 15
        # write the text into the frame
        cv2.putText(frame, label, (start_x, yPos),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), thickness=2)
        # draw the rectangle around the face
        cv2.rectangle(frame, (start_x, start_y), (end_x, end_y), color=(255, 0, 0), thickness=2)
    # Display processed image
    display_img('Age Estimator', frame)
    # save the image if you want
    # cv2.imwrite("predicted_age.jpg", frame)

OpenCV如何检测年龄?下面是上述函数的完整过程:

  • 我们使用该cv2.imread()方法读取图像。
  • 将图像调整为适当的大小后,我们使用我们的get_faces()函数来获取所有检测到的人脸。
  • 我们对每个人脸图像进行迭代,将其设置为年龄预测模型的输入以执行年龄预测。
  • 我们打印每个类别的概率,以及主要类别。
  • 在图像上绘制了一个包含年龄的矩形和文本。
  • 最后,我们展示最终的图像。

你可以随时取消注释该cv2.imwrite()行以保存新图像。

OpenCV年龄检测示例 - 现在让我们编写我们的主要代码:

if __name__ == '__main__':
    # Parsing command line arguments entered by user
    import sys
    image_path = sys.argv[1]
    predict_age(image_path)

我们简单地使用 Python 的内置 sys 模块来获取用户输入,因为我们只需要来自用户的一个参数,那就是图像路径,该argparse模块将是矫枉过正。

让我们在这张库存照片上测试代码:

$ python predict_age.py 3-people.jpg

输出:

============================== Face 1 Prediction Probabilities ==============================
(0, 2): 0.00%
(4, 6): 0.00%
(8, 12): 31.59%
(15, 20): 0.52%
(25, 32): 52.80%
(38, 43): 14.89%
(48, 53): 0.18%
(60, 100): 0.01%
Age:(25, 32) - 52.80%
============================== Face 2 Prediction Probabilities ==============================
(0, 2): 0.00%
(4, 6): 0.05%
(8, 12): 17.63%
(15, 20): 0.02%
(25, 32): 82.22%
(38, 43): 0.06%
(48, 53): 0.01%
(60, 100): 0.00%
Age:(25, 32) - 82.22%
============================== Face 3 Prediction Probabilities ==============================
(0, 2): 0.05%
(4, 6): 0.03%
(8, 12): 0.07%
(15, 20): 0.00%
(25, 32): 1.05%
(38, 43): 0.96%
(48, 53): 86.54%
(60, 100): 11.31%
Age:(48, 53) - 86.54%

这是生成的图像:

如何在Python中使用OpenCV进行年龄检测?

OpenCV年龄检测总结

年龄检测模型严重偏向于年龄组[25-32]。因此,你可以在测试此实用程序时查明此差异。

OpenCV检测年龄示例:你可以随时调整一些参数以使模型更准确。例如,在get_faces()函数中,我将框的四边都加宽了 10 个像素,你可以随时将其更改为你感觉良好的任何值。改变frame_widthframe_height也是提炼预测准确度的一种方式。

如果你想在你的网络摄像头上使用这个模型,我专门为它制作了这个代码。

查看此页面以获取完整的代码版本。

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: