码迷,mamicode.com
首页 > 编程语言 > 详细

Python 3 利用 Dlib 19.7 和 sklearn机器学习模型 实现人脸微笑检测

时间:2018-01-28 14:38:54      阅读:578      评论:0      收藏:0      [点我收藏+]

标签:for   接下来   numpy   www   ilb   orm   append   sel   mac   

0.引言

   利用机器学习的方法训练微笑检测模型,输入一张人脸照片,判断是否微笑;

    识别精度在95%附近(使用的数据集中69张没笑脸,65张有笑脸);

   效果:

 技术分享图片

    图1 测试图像与检测结果

 

   工程利用python 3 开发,借助Dlib进行 人脸嘴部20个特征点坐标(40维特征)的提取;

   然后根据这 40维输入特征 作为模型输入, 1维特征(1代表有微笑 / 0代表没微笑)作为输出,进行ML建模;

   利用几种机器学习模型进行建模,达到一个二分类(分类有/无笑脸)的目的,然后分析模型识别精度和性能,并且可以识别给定图片的人脸是否微笑;

   

  py文件:

   1. Get_features.py : 

      returnfeatures():  输入人脸图像路径,利用dlib的“shape_predictor_68_face_landmarks.dat”提取嘴部20个特征点坐标的40个特征值;

      writeintoCSV():  将40维特征输入和1维的输出标记(1代表有微笑/0代表没微笑)写入CSV文件中;

   2. ML_ways.py:

      pre_data():    读取CSV中的数据,然后提取出训练集和测试集;

      way_LR():     Logistic Regressio, 罗吉斯特回归方法建模;

      way_SGD():  Stochastic Gradient Decent, 随机梯度下降法建模;

      way_SVM():  Supported Vector Machine, 支持向量机法建模;

      way_MLP():   Multi-Layer Perceptron, 多层神经网络法建模;

   3. test_single_pic.py:

   输入给定测试图像,用ML模型检测其有/无笑脸;

   (实现稍微比较复杂,感兴趣的可以结合之前博客看看:

   Python 3 利用 Dlib 19.7 进行人脸识别:

    http://www.cnblogs.com/AdaminXie/p/7905888.html

      Python 3 利用 Dlib 19.7 进行人脸68个特征点的标定:

    http://www.cnblogs.com/AdaminXie/p/8137580.html

   Python 3 利用机器学习模型进行手写体识别:

    http://www.cnblogs.com/AdaminXie/p/8249858.html

 

1.开发环境

  python:  3.6.3

  dlib:    19.7

  OpenCv, numpy, sklearn, pandas, os, csv等

 

  Get_features.py中调用的库:

1 import dlib         # 人脸识别的库dlib
2 import numpy as np  # 数据处理的库numpy
3 import cv2          # 图像处理的库OpenCv
4 import os           # 读取文件
5 import csv          # csv操作

   ML_ways.py中调用的库:

 1 # pd读取CSV
 2 import pandas as pd
 3 
 4 # 分割数据
 5 from sklearn.model_selection import train_test_split
 6 
 7 # 用于数据预加工标准化
 8 from sklearn.preprocessing import StandardScaler
 9 
10 # 使用的四种ML模型
11 from sklearn.linear_model import LogisticRegression
12 from sklearn.linear_model import SGDClassifier
13 from sklearn.svm import LinearSVC
14 from sklearn.neural_network import MLPClassifier

  

  使用的人脸来自于 The MUCT Face Database(Link: http://www.milbo.org/muct/),在此十分感谢!

  (The MUCT database was prepared by Stephen Milborrow, John Morkel, and Fred Nicolls in December 2008 at the University Of Cape Town. We would like to send out a thanks to the people who allowed their faces to be used.)

 

2.设计流程

  工作内容主要以下两大块提取人脸特征 ML建模

  整体的设计流程如下图所示:

  技术分享图片

    图2 总体设计流程图

 

  2.1 提取人脸特征:

    该部分的设计流程图:

  技术分享图片

   图3 人脸提取特征部分流程图 

    我先在项目目录下建立两个文件夹,分别存放有笑脸的人脸,和无笑脸的人脸,这样之后读取的时候就可以知道人脸的标记有/无人脸;

    关于利用dlib进行人脸68个特征点的提取,在我之前另一篇博客里面介绍过:

    (link: http://www.cnblogs.com/AdaminXie/p/7905888.html);

    本项目中只使用其中嘴部20个特征点的坐标作为特征输入,20个点的序号如下图所示:  

  技术分享图片

    图4 dlib标定的嘴部特征点序号

 

  20个特征点40个坐标值,和输出标记的获取,由returnfeatures函数实现;

  输入图像文件所在路径,返回的的是数组features_csv(前40个为特征点坐标值,第41个为标记(1代表有笑脸,0代表无笑脸))

 1 # ML_smiles
 2 # 2018-1-27
 3 # By TimeStamp
 4 # cnblogs: http://www.cnblogs.com/AdaminXie/
 5 
 6 
 7 detector = dlib.get_frontal_face_detector()
 8 predictor = dlib.shape_predictor(shape_predictor_68_face_landmarks.dat)
 9 
10 # 输入图像文件所在路径,返回一个41维数组(包含提取到的40维特征和1维输出标记)
11 def returnfeatures(path_pic, XXXpic, features_csv):
12 
13     # 输入:  path_pic:    图像文件所在目录
14     #       XXXpic:      图像文件名
15 
16     # 输出:  features_csv 41维度的数组,前40维为(提取的20个特征点坐标的40个值),第41维为标记output
17 
18     # 比如 path_pic + XXXpic = "F:/code/test.jpg" 精确到jpg
19     img = cv2.imread(path_pic + XXXpic)
20     # 取灰度
21     img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
22 
23     # 计算68点坐标
24     pos_68 = []
25     rects = detector(img_gray, 0)
26     landmarks = np.matrix([[p.x, p.y] for p in predictor(img, rects[0]).parts()])
27     for idx, point in enumerate(landmarks):
28         # 68点的坐标
29         pos = (point[0, 0], point[0, 1])
30         pos_68.append(pos)
31 
32     # 将点49-68写入csv
33     # 即pos_68[48]-pos_68[67]
34     for i in range(48, 68):
35         features_csv.append(pos_68[i][0])
36         features_csv.append(pos_68[i][1])
37 
38     #print(features_csv)
39     return features_csv

 

  然后就遍历两个存放有/无笑脸的文件夹,读取图像文件,然后利用returnfeatures()函数得到特征值,写入CSV中:

 1 # ML_smiles
 2 # 2018-1-27
 3 # By TimeStamp
 4 # cnblogs: http://www.cnblogs.com/AdaminXie/
 5 # Get_features.py
 6 
 7 
 8 # 读取图像所在的路径
 9 path_pic_smile = "F:/code/python/P_ML_smile/pic/database/smile/"
10 path_pic_nosmile = "F:/code/python/P_ML_smile/pic/database/no/"
11 
12 # 获取路径下的图像文件
13 namedir_smile = os.listdir(path_pic_smile)
14 namedir_nosmile = os.listdir(path_pic_nosmile)
15 
16 # 存储提取特征数据的CSV的路径
17 path_csv = "F:/code/python/P_ML_smile/data_csv/"
18 
19 def writeintoCSV():
20     with open(path_csv+"data.csv", "w", newline="") as csvfile:
21         writer = csv.writer(csvfile)
22 
23         # 处理带笑脸的图像
24         print("######## with smiles #########")
25         for i in range(len(namedir_smile)):
26             print("pic:", path_pic_smile, namedir_smile[i])
27 
28             # 用来存放41维特征
29             features_csv_smiles = []
30 
31             # 利用 returnfeatures 函数提取特征
32             returnfeatures(path_pic_smile, namedir_smile[i], features_csv_smiles)
33             features_csv_smiles.append(1)
34             print("features:", features_csv_smiles, "\n")
35 
36             # 写入CSV
37             writer.writerow(features_csv_smiles)
38 
39         # 处理不带笑脸的图像
40         print("######## no smiles #########")
41         for i in range(len(namedir_nosmile)):
42             print("pic:", path_pic_nosmile, namedir_nosmile[i])
43 
44             # 用来存放41维特征
45             features_csv_nosmiles = []
46 
47             # 利用 returnfeatures 函数提取特征
48             returnfeatures(path_pic_nosmile, namedir_nosmile[i], features_csv_nosmiles)
49             features_csv_nosmiles.append(0)
50             print("features:", features_csv_nosmiles, "\n")
51 
52             # 写入CSV
53             writer.writerow(features_csv_nosmiles)

  会得到一个41列的CSV文件,前40列为40维的输入特征,第41列为笑脸标记。   

 

  2.2 ML建模和测试

    这部分机器学习模型使用比较简单,之前的特征提取已经完成,写入了CSV文件中;

    接下来就是要从CSV中将想要的数据集提取出来,利用sklearn进行机器学习建模。

  2.2.1 数据预加工

    利用pands.read_csv读取CSV文件,然后利用train_test_split进行数据分割;

    得到 训练集:X_train, y_train测试集:X_test, y_test

 1 # ML_smiles
 2 # 2018-1-27
 3 # By TimeStamp
 4 # cnblogs: http://www.cnblogs.com/AdaminXie/
 5 # pre_data() in ML_ways.py
 6 
 7 
 8 # 从CSV读取数据
 9 def pre_data():
10 
11     # 41维表头
12     column_names = []
13     for i in range(0, 40):
14         column_names.append("feature_" + str(i+1))
15     column_names.append("output")
16 
17     path_csv = "F:/code/python/P_ML_smile/data_csv/"
18 
19     rd_csv = pd.read_csv(path_csv+"data.csv", names=column_names)
20 
21     # 输出CSV文件的维度
22     print("shape:", rd_csv.shape)
23 
24     global X_train, X_test, y_train, y_test
25     X_train, X_test, y_train, y_test = train_test_split(
26         rd_csv[column_names[0:40]],
27         rd_csv[column_names[40]],
28         test_size=0.25,
29         random_state=33)

 

  2.2.2 机器学习建模

    几种建模方法在sklearn中实现的代码类似,所以在此只介绍LR,Logisitic Regression罗吉斯特回归方法;

    返回ss_LR和LR,需要这两个返回值,是因为之后要利用它们对给定图像的进行检测,之后2.2.3节会介绍;

 1 # ML_smiles
 2 # 2018-1-27
 3 # By TimeStamp
 4 # cnblogs: http://www.cnblogs.com/AdaminXie/
 5 # way_LR() in ML_ways.py
 6 
 7 # 罗吉斯特回归LR
 8 def way_LR():
 9 
10     X_train_LR = X_train
11     y_train_LR = y_train
12 
13     X_test_LR = X_test
14     y_test_LR = y_test
15 
16     # 标准化数据预加工
17     ss_LR = StandardScaler()
18 
19     X_train_LR = ss_LR.fit_transform(X_train_LR)
20     X_test_LR = ss_LR.transform(X_test_LR)
21 
22     # 初始化LogisticRegression
23     LR = LogisticRegression()
24 
25     # 调用LogisticRegression中的fit()来训练模型参数
26     LR.fit(X_train_LR, y_train_LR)
27 
28     # 使用训练好的模型lr对X_test进行预测,结果储存在lr_y_predict中
29     global y_predict_LR
30     y_predict_LR = LR.predict(X_test_LR)
31 
32     global lr_score
33     lr_score=LR.score(X_test_LR, y_test_LR)
34     print("The accurary of LR:", LR.score(X_test_LR, y_test_LR))
35 
36     return ss_LR, LR

 

  我的数据集里面是69张没笑脸,65张有笑脸,测试精度如下,精度在95%附近:

The accurary of LR: 0.941176470588
The accurary of SGD: 0.882352941176
The accurary of SVM: 0.941176470588
The accurary of MLP: 0.970588235294

 

  2.2.3 测试单张图片

  现在我们已经建好机器学习模型,在2.2.2中可以利用sklearn机器学习模型的score函数得到模型精度,但是如果想检测给定图像的笑脸,需要进行该部分工作:

  path_test_pic+XXXpic就是需要进行检测的文件路径,需要精确到图像文件,比如“F:/pic/test.pic”;

  然后调用Get.features.py中的returnfeatures()函数进行特征提取,得到给定图像的40维特征数组single_features;

  如果想利用LR模型测试,接受way_LR()的返回值ss_LR和LR,利用ss_LR对single_features进行标准化处理,然后调用LR.predict进行预测;

  然后生成图像窗口,将几种模型的结果显示在图像上。

 1 # ML_smiles
 2 # 2018-1-27
 3 # By TimeStamp
 4 # cnblogs: http://www.cnblogs.com/AdaminXie/
 5 # test_single_pic.py
 6 
 7 import cv2
 8 
 9 from ML_ways import pre_data
10 from ML_ways import way_LR
11 from ML_ways import way_MLP
12 from ML_ways import way_SGD
13 from ML_ways import way_SVM
14 
15 # 获得单张人脸的特征点
16 path_test_pic = "F:/code/python/P_ML_smile/pic/"
17 #path_test_pic = "F:/code/pic/faces/the_muct_face_database/jpg/"
18 
19 XXXpic = "test1.jpg"
20 
21 # 训练LR模型
22 pre_data()
23 
24 # 使用标准化参数和ML模型
25 ss_LR, LR = way_LR()
26 ss_SGD, SGD = way_SGD()
27 ss_SVM, SVM = way_SVM()
28 ss_MLP, MLP = way_MLP()
29 
30 # 提取单张40维度特征
31 from Get_features import returnfeatures
32 single_features = []
33 returnfeatures(path_test_pic, XXXpic, single_features)
34 #print("single_40_features: ", single_features)
35 
36 ############## LR模型预测 ##############
37 
38 # 特征数据预加工
39 X_single_LR = ss_LR.transform([single_features])
40 # 利用训练好的LR模型预测
41 y_predict_LR_single = LR.predict(X_single_LR)
42 
43 con_LR = str(y_predict_LR_single[0]).replace("1", "smiles").replace("0", "no_smiles")
44 print("LR:", con_LR)
45 
46 ############## SGD模型预测 ##############
47 
48 # 特征数据预加工
49 X_single_SGD = ss_SGD.transform([single_features])
50 # 利用训练好的SGD模型预测
51 y_predict_SGD_single = SGD.predict(X_single_SGD)
52 
53 con_SGD = str(y_predict_SGD_single[0]).replace("1", "smiles").replace("0", "no_smiles")
54 print("SGD:", con_SGD)
55 
56 ############## SVM模型预测 ##############
57 
58 # 特征数据预加工
59 X_single_SVM = ss_SVM.transform([single_features])
60 # 利用训练好的SVM模型预测
61 y_predict_SVM_single = SVM.predict(X_single_SVM)
62 
63 con_SVM = str(y_predict_SVM_single[0]).replace("1", "smiles").replace("0", "no_smiles")
64 print("SVM:", con_SVM)
65 
66 ############## MLP模型预测 ##############
67 
68 # 特征数据预加工
69 X_single_MLP = ss_MLP.transform([single_features])
70 # 利用训练好的MLP模型预测
71 y_predict_MLP_single = MLP.predict(X_single_MLP)
72 
73 con_MLP = str(y_predict_MLP_single[0]).replace("1", "smiles").replace("0", "no_smiles")
74 print("MLP:", con_MLP)
75 
76 img = cv2.imread(path_test_pic+XXXpic)
77 
78 font = cv2.FONT_HERSHEY_SIMPLEX
79 
80 cv2.putText(img, "LR: "+con_LR, (20, 50), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
81 cv2.putText(img, "SGD: "+con_SGD, (20, 100), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
82 cv2.putText(img, "SVM: "+con_SVM, (20, 150), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
83 cv2.putText(img, "MLP: "+con_MLP, (20, 200), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
84 
85 cv2.namedWindow("img")#, 2)
86 cv2.imshow("img", img)
87 cv2.waitKey(0)

 

3.效果

  技术分享图片

  图5 同一个人不同表情的笑脸检测结果

 

4.总结

  自己最近经常使用dlib做人脸识别这块,又在学习机器学习,两者结合尝试做到笑容检测这块;

  数据集中有无笑脸是自己进行分类的,而且有写的表情不太好界定,所以选取的是一些笑容比较明显的照片作为有笑脸,所以可能出来模型在检测一些微笑上有误差;

  笑容检测模型的数据集测试精度在95%左右,比较理想;

  其实人脸笑容检测的话,光靠嘴部特征去判断不太合适,要结合整张人脸特征点进行训练,改进的话也比较简单;

 

# 请尊重他人劳动成果,转载或者使用源码请注明出处(http://www.cnblogs.com/AdaminXie/

# 交流学习可以联系邮箱 coneypo@foxmail.com

Python 3 利用 Dlib 19.7 和 sklearn机器学习模型 实现人脸微笑检测

标签:for   接下来   numpy   www   ilb   orm   append   sel   mac   

原文地址:https://www.cnblogs.com/AdaminXie/p/8367348.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!