基于OpenCV和tensorflow的人脸关键点检测
转载请注明出处https://blog.csdn.net/weixin_40336829/article/details/85456271
引言
最近利用tengine平台做了一个移植到andriod端的app。本人负责训练人脸关键点检测的模型。考虑到tengine平台对tensorflow支持较少,故实现的模型也较为简单。这里主要记录基于tensorflow生成ckpt模型和pb模型的一些方法以及结合opencv在PC端实现实时的人脸关键点检测。
人脸关键点数据集
数据集主要使用了kaggle上Facial Keypoints Detection网址: [https://www.kaggle.com/c/facial-keypoints-detection].比赛提供的数据集。该数据集包含包括7,049幅图像,96 x 96像素的灰度图像。预测15个人脸关键点。数据集中每一张图片刚好包含整个人脸,需要检测的15个人脸关键点如下图所示。
数据集图片:
tensorflow模型搭建
这次的人脸关键点检测可以看作是一个回归问题。本文使用3层CNN和3层全连接层作为一个baseline。
首先先对数据集进行预处理 预处理代码如下
.input_data函数主要是将输入96*96图片的像素值归一化到[0,1]的区间内,而要预测的15个关键点的坐标(x,y)也归一化到[0,1]的区间内。
import pandas as pd
import numpy as np
def input_data(test=False):
file_name = TEST_FILE if test else TRAIN_FILE
df = pd.read_csv(file_name)
cols = df.columns[:-1]
#dropna()是丢弃有缺失数据的样本,这样最后7000多个样本只剩2140个可用的。
df = df.dropna()
df['Image'] = df['Image'].apply(lambda img: np.fromstring(img, sep=' ') / 255.0)
X = np.vstack(df['Image'])
X = X.reshape((-1,96,96,1))
if test:
y = None
else:
y = df[cols].values / 96.0 #将y值缩放到[0,1]区间
return X, y
定义卷积池化操作
import tensorflow as tf
#根据给定的shape定义并初始化卷积核的权值变量
def weight_variable(shape,namew='w'):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial,name=namew)
#根据shape初始化bias变量
def bias_variable(shape,nameb='b'):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial,name=nameb)
#定义卷积操作
def conv2d(x,W):
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='VALID')
#定义池化操作
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME')
pb文件的生成
pb文件相比于ckpt文件较为简化,所有的网络结构及参数均保存为一个pb文件。利用tensorflow训练模型并生成.pb文件,这里主要介绍一个简单的方法来生成。
//生成pb文件所需要的graph_util库,用于在pb模型中保存模型的名称,方便调用pb模型
from tensorflow.python.framework import graph_util
下面为完整的模型训练及保存代码
import tensorflow as tf
TRAIN_FILE = 'training.csv'
TEST_FILE = 'test.csv'
SAVE_PATH = './model2' #模型保存路径
VALIDATION_SIZE = 100 #验证集大小
EPOCHS = 100 #迭代次数
BATCH_SIZE = 64 #每个batch大小,稍微大一点的batch会更稳定
EARLY_STOP_PATIENCE = 20 #控制early stopping的参数
#保存模型函数
def save_model(saver,sess,save_path):
path = saver.save(sess, save_path)
print('model save in :{0}'.format(path))
with tf.Session(graph=tf.Graph()) as sess:
#定义的模型,生成pb文件需要对输入x和输出y命名,这里将输入x命名为input,输入y命名为output,同时如果有dropout参数也需进行命名。
x = tf.placeholder("float", shape=[None, 96, 96, 1],name='input')#输入占位
y_ = tf.placeholder("float", shape=[None, 30],name='y')#输出占位
keep_prob = tf.placeholder("float",name='keep_prob')#dropout概率值
W_conv1 = weight_variable([3, 3, 1, 32],'w1')#32个3*3*1的卷积核
b_conv1 = bias_variable