• Keras深度学习实战(12)——面部特征点检测


    0. 前言

    在计算机视觉中,面部关键点(也称为面部特征点)的定位通常是许多面部分析方法和算法中的关键步骤。在本节中,我们将训练卷积神经网络来检测面部的关键点,即左右眼,鼻子和嘴巴的四个坐标的边界。以下是两个绘制了面部关键点的示例图片:

    面部关键点示例
    如上图所示,检测到的关键点此图中被绘制为点。在人脸图像上共检测 68 个关键点,其中面部关键点包括:嘴,右眉,左眉,右眼,左眼,鼻子,下巴。在本文中,我们将基于预训练 VGG16 架构提取图像特征,然后微调模型检测图像中人物面部关键点。

    1. 数据集和模型分析

    1.1 数据集分析

    对于关键点检测任务,我们所使用的数据集可以从 Github下载,数据集中标注了中图片的人物面部的关键点。在此任务中,输入数据是需要在其上检测关键点的图像,输出数据是图像中人物面部关键点的 xy 坐标。
    在构建模型前,首先将数据集下载至本地,查看数据集中标记的面部关键点信息,文件路径为 P1_Facial_Keypoints/data/training_frames_keypoints.csv

    数据集
    检查此数据集中的面部关键点信息,可以看到,文件中共有 137 列,其中第一列是图像的名称,其余 136 列代表相应图像中 68 个面部关键点的 xy 坐标值。

    1.2 模型分析

    接下来,继续分析此任务以及我们将使用的模型架构:

    • 根据关键点检测任务,下载数据集
    • 将图像调整为可以用于网络输入的形状
      • 调整图像大小时,需要确保同时修改关键点,以便它们可以对应于已调整大小后的图像
    • 使用预训练的 VGG16 模型提取输入图像特征
    • 创建面部关键点检测任务的输入和输出数组,其中输入数组是通过 VGG16 模型处理后的图像特征,而输出数组是修改后的面部关键点位置坐标
    • 最后,训练模型以减少面部预测关键点与实际关键点之间的绝对平均误差值

    2. 面部特征点检测

    本节中,我们将编程实现上一节中所分析的面部关键点检测模型。
    导入相关库、数据集,并实例化预训练的 `VGG16模型:

    import pandas as pd
    import cv2
    import numpy as np
    from copy import deepcopy
    from keras.applications.vgg16 import preprocess_input
    from keras.applications import vgg16
    from matplotlib import pyplot as plt
    
    data = pd.read_csv('P1_Facial_Keypoints/data/training_frames_keypoints.csv')
    vgg16_model = vgg16.VGG16(include_top=False, weights='imagenet',input_shape=(224,224,3))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    预处理数据集,包括:提取图像、调整图像尺寸、获得 VGG16 提取到的图像特征,并将根据缩放图像修改的面部关键点位置作为输出。
    初始化用于创建输出和输出的列表:

    x = []
    x_img = []
    y = []
    
    • 1
    • 2
    • 3

    循环构建图像文件名,并读取图像:

    for i in range(data.shape[0]):
        img_path = 'P1_Facial_Keypoints/data/training/' + data.iloc[i,0]
        img = cv2.imread(img_path)
    
    • 1
    • 2
    • 3

    捕获面部关键点值并进行存储,然后调整图像大小,以满足模型输入形状,并预处理图像,以便可以将其传递给 VGG16 模型并提取特征::

        kp = deepcopy(data.iloc[i,1:].tolist())
        kp_x = (np.array(kp[0::2])/img.shape[1]).tolist()
        kp_y = (np.array(kp[1::2])/img.shape[0]).tolist()
        kp2 = kp_x +kp_y
        img = cv2.resize(img, (224, 224))
        preprocess_img = preprocess_input(img.reshape(1,224,224,3))
        vgg16_img = vgg16_model.predict(preprocess_img)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    将输入和输出值追加到相应的列表中:

        x_img.append(img)
        x.append(vgg16_img)
        y.append(kp2)
    
    • 1
    • 2
    • 3

    创建输入和输出数组:

    x = np.array(x)
    x = x.reshape(x.shape[0], x.shape[2], x.shape[3], x.shape[4])
    y = np.array(y)
    
    • 1
    • 2
    • 3

    建立并编译模型

    from keras.models import Sequential
    from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
    model_fine_tuning = Sequential()
    model_fine_tuning.add(Conv2D(512, kernel_size=(3, 3), activation='relu',input_shape=(x.shape[1],x.shape[2],x.shape[3])))
    model_fine_tuning.add(MaxPooling2D(pool_size=(2, 2)))
    model_fine_tuning.add(Flatten())
    model_fine_tuning.add(Dense(512, activation='relu'))
    model_fine_tuning.add(Dropout(0.5))
    model_fine_tuning.add(Dense(y.shape[1], activation='sigmoid'))
    model_fine_tuning.summary()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出用于检测面部关键点的微调模型简要信息如下:

    Model: "sequential"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    conv2d (Conv2D)              (None, 5, 5, 512)         2359808   
    _________________________________________________________________
    max_pooling2d (MaxPooling2D) (None, 2, 2, 512)         0         
    _________________________________________________________________
    flatten (Flatten)            (None, 2048)              0         
    _________________________________________________________________
    dense (Dense)                (None, 512)               1049088   
    _________________________________________________________________
    dropout (Dropout)            (None, 512)               0         
    _________________________________________________________________
    dense_1 (Dense)              (None, 136)               69768     
    =================================================================
    Total params: 3,478,664
    Trainable params: 3,478,664
    Non-trainable params: 0
    _________________________________________________________________
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    最后,编译并拟合模型:

    model_fine_tuning.compile(loss='mean_absolute_error',optimizer='adam')
    history = model_fine_tuning.fit(x/np.max(x), y,
                                epochs=10,
                                batch_size=32,
                                verbose=1,
                                validation_split = 0.1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    需要注意的是,我们将输入数组除以输入数组的最大值,以缩放输入数据集,而 validation_split 可选参数用于在没有提供验证集的时候,按一定比例(此处为 10% )从训练集中取出一部分训练数据作为测试集。训练和测试损失随 epoch 增加的变化情况如下:

    训练过程监测

    3. 模型测试

    预测测试图像。在下面的代码中,我们预测输入数组中倒数第 6 和第 7 个图像,由于 validation_split0.1,训练时模型并未见到这 2 张图像,可以用于衡量训练后的模型性能。我们确保将图像通过 preprocess_input 方法进行预处理,然后通过 vgg16_model 提取图像特征,最后将 vgg16_model 的输出传递给构建的 model_fine_tuning

    test_img_input = preprocess_input(x_img[-7].reshape(1,224,224,3))
    pred = model_fine_tuning.predict(vgg16_model.predict(test_img_input/np.max(test_img_input)))
    
    plt.subplot(221)
    plt.title('Original image')
    plt.imshow(cv2.cvtColor(x_img[-7], cv2.COLOR_BGR2RGB))
    plt.subplot(222)
    plt.title('Image with facial keypoints')
    plt.imshow(cv2.cvtColor(x_img[-7], cv2.COLOR_BGR2RGB))
    kp = pred.flatten()
    plt.scatter(kp[0:68]*224, kp[68:]*224)
    
    test_img_input = preprocess_input(x_img[-6].reshape(1,224,224,3))
    pred = model_fine_tuning.predict(vgg16_model.predict(test_img_input/np.max(test_img_input)))
    
    plt.subplot(223)
    plt.title('Original image')
    plt.imshow(cv2.cvtColor(x_img[-6], cv2.COLOR_BGR2RGB))
    plt.subplot(224)
    plt.title('Image with facial keypoints')
    plt.imshow(cv2.cvtColor(x_img[-6], cv2.COLOR_BGR2RGB))
    kp = pred.flatten()
    plt.scatter(kp[0:68]*224, kp[68:]*224)
    plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    先前对测试图像的预测可以如下所示,我们可以看到,在测试图像上可以非常准确地检测到图片中人物的面部关键点。

    模型测试

    小结

    面部关键点的定位通常是许多面部分析方法和算法中的关键步骤。在本节中,我们介绍了如何通过训练卷积神经网络来检测面部的关键点,首先通过预训练模型提取特征,然后利用微调模型预测图像中人物的面部关键点。

    系列链接

    Keras深度学习实战(1)——神经网络基础与模型训练过程详解
    Keras深度学习实战(2)——使用Keras构建神经网络
    Keras深度学习实战(3)——神经网络性能优化技术
    Keras深度学习实战(4)——深度学习中常用激活函数和损失函数详解
    Keras深度学习实战(5)——批归一化详解
    Keras深度学习实战(6)——深度学习过拟合问题及解决方法
    Keras深度学习实战(7)——卷积神经网络详解与实现
    Keras深度学习实战(8)——使用数据增强提高神经网络性能
    Keras深度学习实战(9)——卷积神经网络的局限性
    Keras深度学习实战(10)——迁移学习
    Keras深度学习实战(11)——可视化神经网络中间层输出

  • 相关阅读:
    git快速查看某个文件修改的所有commit
    PT_随机变量函数的分布_随机变量线性函数的正态分布
    误删 performance_schema 后恢复
    webpack之处理字体图标资源和打包其他资源
    k8s集群中pod的容器资源限制和三种探针
    从今天起真正释放创造力 | Werner Vogels 在 re:Invent 2022带来多项开发者福音
    用户身份标识与账号体系实践
    01_什么是深度学习
    文档参考888
    【漏洞复现】Django _2.0.8_任意URL跳转漏洞(CVE-2018-14574)
  • 原文地址:https://blog.csdn.net/LOVEmy134611/article/details/124647818