一.实验准备
下载实验所需包
pip install scikit-image
pip install playsound
pip install pandas
pip install sklearn
二.图片预处理
这里图片的预处理包括人脸识别裁剪,数据集划分,具体操作和https://blog.csdn.net/qq_45659777/article/details/121728481处第二步相同,就不过多描述了。
数据划分
新建文件目录如下:
在database下的图片按照人脸表情分别放在两个文件夹中,幸好这里的图片笑脸和非笑脸是分开的。
三.Dlib提取人脸特征
通过上一步已经得到了人脸的图片,这里要进行dlib特征点提取。
我们这里只需要提取嘴部20个特征点坐标的40个特征值就可以了,将提取的特征值写入表格。
代码:
# 从人脸图像文件中提取人脸特征存入 CSV
# Features extraction from images and save into features_all.csv
# return_128d_features() 获取某张图像的128D特征
# compute_the_mean() 计算128D特征均值
from cv2 import cv2 as cv2
import os
import dlib
from skimage import io
import csv
import numpy as np
# 要读取人脸图像文件的路径
path_images_from_camera = "D:/myworkspace/JupyterNotebook/Smile/files2/test/"
# Dlib 正向人脸检测器
detector = dlib.get_frontal_face_detector()
# Dlib 人脸预测器
predictor = dlib.shape_predictor("D:/shape_predictor_68_face_landmarks.dat")
# Dlib 人脸识别模型
# Face recognition model, the object maps human faces into 128D vectors
face_rec = dlib.face_recognition_model_v1("D:/dlib_face_recognition_resnet_model_v1.dat")
# 返回单张图像的 128D 特征
def return_128d_features(path_img):
img_rd = io.imread(path_img)
img_gray = cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB)
faces = detector(img_gray, 1)
print("%-40s %-20s" % ("检测到人脸的图像 / image with faces detected:", path_img), '\n')
# 因为有可能截下来的人脸再去检测,检测不出来人脸了
# 所以要确保是 检测到人脸的人脸图像 拿去算特征
if len(faces) != 0:
shape = predictor(img_gray, faces[0])
face_descriptor = face_rec.compute_face_descriptor(img_gray, shape)
else:
face_descriptor = 0
print("no face")
return face_descriptor
# 将文件夹中照片特征提取出来, 写入 CSV
def return_features_mean_personX(path_faces_personX):
features_list_personX = []
photos_list = os.listdir(path_faces_personX)
if photos_list:
for i in range(len(photos_list)):
# 调用return_128d_features()得到128d特征
print("%-40s %-20s" % ("正在读的人脸图像 / image to read:", path_faces_personX + "/" + photos_list[i]))
features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i])
# print(features_128d)
# 遇到没有检测出人脸的图片跳过
if features_128d == 0:
i += 1
else:
features_list_personX.append(features_128d)
i1=str(i+1)
add="D:/myworkspace/JupyterNotebook/Smile/feature/face_feature"+i1+".csv"
print(add)
with open(add, "w", newline="") as csvfile:
writer1 = csv.writer(csvfile)
writer1.writerow(features_128d)
else:
print("文件夹内图像文件为空 / Warning: No images in " + path_faces_personX + '/', '\n')
# 计算 128D 特征的均值
# N x 128D -> 1 x 128D
if features_list_personX:
features_mean_personX = np.array(features_list_personX).mean(axis=0)
else:
features_mean_personX = '0'
return features_mean_personX
# 读取某人所有的人脸图像的数据
people = os.listdir(path_images_from_camera)
people.sort()
with open("D:/myworkspace/JupyterNotebook/Smile/feature/features2_all.csv", "w", newline="") as csvfile:
writer = csv.writer(csvfile)
for person in people:
print("##### " + person + " #####")
# Get the mean/average features of face/personX, it will be a list with a length of 128D
features_mean_personX = return_features_mean_personX(path_images_from_camera + person)
writer.writerow(features_mean_personX)
print("特征均值 / The mean of features:", list(features_mean_personX))
print('\n')
print("所有录入人脸数据存入 / Save all the features of faces registered into: D:/myworkspace/JupyterNotebook/Smile/feature/features2_all.csv")
在这一步由于某些图片不能被识别到,所以会报错,那么需要将图片进一步处理,比如删除,不过工作量有点大。
实在是太累了,smile只提取了1001张图片,nosmile提取了838张。
运行结果:
smile:
nosmile:
将数据合并到一个文件。
四.微笑识别
1.建立模型
读取data.csv中的数据,提取训练集X_train和测试集X_test。
代码:
# pandas 读取 CSV
import pandas as pd
# 分割数据
from sklearn.model_selection import train_test_split
# 用于数据预加工标准化
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression # 线性模型中的 Logistic 回归模型
from sklearn.neural_network import MLPClassifier # 神经网络模型中的多层网络模型
from sklearn.svm import LinearSVC # SVM 模型中的线性 SVC 模型
from sklearn.linear_model import SGDClassifier # 线性模型中的随机梯度下降模型
import joblib
# 从 csv 读取数据
def pre_data():
# 41 维表头
column_names = []
for i in range(0, 40):
column_names.append("feature_" + str(i + 1))
column_names.append("output")
# read csv
rd_csv = pd.read_csv("D:/myworkspace/JupyterNotebook/Smile/data/data_csvs/data.csv", names=column_names)
# 输出 csv 文件的维度
# print("shape:", rd_csv.shape)
X_train, X_test, y_train, y_test = train_test_split(
# input 0-40
# output 41
rd_csv[column_names[0:40]],
rd_csv[column_names[40]]