SVM算法应用综合练习--人脸微笑识别
Posted YouthBlood9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SVM算法应用综合练习--人脸微笑识别相关的知识,希望对你有一定的参考价值。
录
一、图片准备
- 图片集:
二、图片预处理
- 我们需要将人脸检测出来并对图片进行裁剪
2.1 代码
import dlib # 人脸识别的库dlib
import numpy as np # 数据处理的库numpy
import cv2 # 图像处理的库OpenCv
import os
# dlib预测器
detector = dlib.get_frontal_face_detector()
# shape_predictor_68_face_landmarks.dat文件的位置 之前有下载过 可见前面的文章里
predictor = dlib.shape_predictor('D:/ProgramData/wenjian/shape_predictor_68_face_landmarks.dat')
# 读取图像的路径
path_read = "D:\\\\**\\\\genki4k\\\\files"
num=0
for file_name in os.listdir(path_read):
#aa是图片的全路径
aa=(path_read +"/"+file_name)
#读入的图片的路径中含非英文
img=cv2.imdecode(np.fromfile(aa, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
#获取图片的宽高
img_shape=img.shape
img_height=img_shape[0]
img_width=img_shape[1]
# 用来存储生成的单张人脸的路径,要先在你的文件里建好files1文件
path_save="D:\\\\**\\\\genki4k\\\\files1"
# dlib检测
dets = detector(img,1)
print("人脸数:", len(dets))
for k, d in enumerate(dets):
if len(dets)>1:
continue
num=num+1
# 计算矩形大小
# (x,y), (宽度width, 高度height)
pos_start = tuple([d.left(), d.top()])
pos_end = tuple([d.right(), d.bottom()])
# 计算矩形框大小
height = d.bottom()-d.top()
width = d.right()-d.left()
# 根据人脸大小生成空的图像
img_blank = np.zeros((height, width, 3), np.uint8)
for i in range(height):
if d.top()+i>=img_height:# 防止越界
continue
for j in range(width):
if d.left()+j>=img_width:# 防止越界
continue
img_blank[i][j] = img[d.top()+i][d.left()+j]
img_blank = cv2.resize(img_blank, (200, 200), interpolation=cv2.INTER_CUBIC)
cv2.imencode('.jpg', img_blank)[1].tofile(path_save+"\\\\"+"file"+str(num)+".jpg") # 正确方法
2.2 实验结果
- 运行结果:
- 文件里结果:
- 共识别出3878张图片。
某些图片没有识别出人脸(运行结果中显示人脸数0),所以没有裁剪保存,可以自行添加图片补充。
三、划分数据集
3.1 代码
import os, shutil
# 原始数据集路径(前面用来存储生成的单张人脸的路径)
original_dataset_dir = 'D:\\\\**\\\\genki4k\\\\files1'
# 新的数据集(这里不用自己新建,会自己生成)
base_dir = 'D:\\\\**\\\\genki4k\\\\files2'
os.mkdir(base_dir)
# 训练图像、验证图像、测试图像的目录
train_dir = os.path.join(base_dir, 'train')
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir, 'test')
os.mkdir(test_dir)
train_cats_dir = os.path.join(train_dir, 'smile')
os.mkdir(train_cats_dir)
train_dogs_dir = os.path.join(train_dir, 'unsmile')
os.mkdir(train_dogs_dir)
validation_cats_dir = os.path.join(validation_dir, 'smile')
os.mkdir(validation_cats_dir)
validation_dogs_dir = os.path.join(validation_dir, 'unsmile')
os.mkdir(validation_dogs_dir)
test_cats_dir = os.path.join(test_dir, 'smile')
os.mkdir(test_cats_dir)
test_dogs_dir = os.path.join(test_dir, 'unsmile')
os.mkdir(test_dogs_dir)
# 复制1000张笑脸图片到train_c_dir
fnames = ['file.jpg'.format(i) for i in range(1,900)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_cats_dir, fname)
shutil.copyfile(src, dst)
fnames = ['file.jpg'.format(i) for i in range(900, 1350)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_cats_dir, fname)
shutil.copyfile(src, dst)
# Copy next 500 cat images to test_cats_dir
fnames = ['file.jpg'.format(i) for i in range(1350, 1800)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_cats_dir, fname)
shutil.copyfile(src, dst)
fnames = ['file.jpg'.format(i) for i in range(2127,3000)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(train_dogs_dir, fname)
shutil.copyfile(src, dst)
# Copy next 500 dog images to validation_dogs_dir
fnames = ['file.jpg'.format(i) for i in range(3000,3878)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_dogs_dir, fname)
shutil.copyfile(src, dst)
# Copy next 500 dog images to test_dogs_dir
fnames = ['file.jpg'.format(i) for i in range(3000,3878)]
for fname in fnames:
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(test_dogs_dir, fname)
shutil.copyfile(src, dst)
3.2 实验结果
- 文件里面分别存放了smile和unsmile文件的图片
四、提取人脸并判别是否为笑脸
4.1 代码
- 导入依赖包:
# 导入包
import numpy as np
import cv2
import dlib
import random#构建随机测试集和训练集
from sklearn.svm import SVC #导入svm
from sklearn.svm import LinearSVC #导入线性svm
from sklearn.pipeline import Pipeline #导入python里的管道
import os
import joblib#保存模型
from sklearn.preprocessing import StandardScaler,PolynomialFeatures #导入多项式回归和标准化
import tqdm
- 图片路径
folder_path='D:/**/genki4k/'
label='labels.txt'#标签文件
pic_folder='files/'#图片文件路径
- 获得默认的人脸检测器和训练好的人脸68特征点检测器:
#获得默认的人脸检测器和训练好的人脸68特征点检测器
def get_detector_and_predicyor():
#使用dlib自带的frontal_face_detector作为我们的特征提取器
detector = dlib.get_frontal_face_detector()
"""
功能:人脸检测画框
参数:PythonFunction和in Classes
in classes表示采样次数,次数越多获取的人脸的次数越多,但更容易框错
返回值是矩形的坐标,每个矩形为一个人脸(默认的人脸检测器)
"""
#返回训练好的人脸68特征点检测器
predictor = dlib.shape_predictor('D:/ProgramData/wenjian/shape_predictor_68_face_landmarks.dat')
return detector,predictor
#获取检测器
detector,predictor=get_detector_and_predicyor()
- 截取面部函数:
def cut_face(img,detector,predictor):
#截取面部
img_gry=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
rects = detector(img_gry, 0)
if len(rects)!=0:
mouth_x=0
mouth_y=0
landmarks = np.matrix([[p.x, p.y] for p in predictor(img,rects[0]).parts()])
for i in range(47,67):#嘴巴范围
mouth_x+=landmarks[i][0,0]
mouth_y+=landmarks[i][0,1]
mouth_x=int(mouth_x/20)
mouth_y=int(mouth_y/20)
#裁剪图片
img_cut=img_gry[mouth_y-20:mouth_y+20,mouth_x-20:mouth_x+20]
return img_cut
else:
return 0#检测不到人脸返回0
- 提取特征值函数:
#提取特征值
def get_feature(files_train,face,face_feature):
for i in tqdm.tqdm(range(len(files_train))):
img=cv2.imread(folder_path+pic_folder+files_train[i])
cut_img=cut_face(img,detector,predictor)
if type(cut_img)!=int:
face.append(True)
cut_img=cv2.resize(cut_img,(64,64))
#padding:边界处理的padding
padding=(8,8)
winstride=(16,16)
hogdescrip=hog.compute(cut_img,winstride,padding).reshape((-1,))
face_feature.append(hogdescrip)
else:
face.append(False)#没有检测到脸的
face_feature.append(0)
- 筛选函数
def filtrate_face(face,face_feature,face_site): #去掉检测不到脸的图片的特征并返回特征数组和相应标签
face_features=[]
#获取标签
label_flag=[]
with open(folder_path+label,'r') as f:
lines=f.read().splitlines()
#筛选出能检测到脸的,并收集对应的label
for i in tqdm.tqdm(range(len(face_site))):
if face[i]:#判断是否检测到脸
#pop之后要删掉当前元素,后面的元素也要跟着前移,所以每次提取第一位就行了
face_features.append(face_feature.pop(0))
label_flag.append(int(lines[face_site[i]][0]))
else:
face_feature.pop(0)
datax=np.float64(face_features)
datay=np.array(label_flag)
return datax,datay
- 多项式SVM:
def PolynomialSVC(degree,c=10):#多项式svm
return Pipeline([
# 将源数据 映射到 3阶多项式
("poly_features", PolynomialFeatures(degree=degree)),
# 标准化
("scaler", StandardScaler()),
# SVC线性分类器
("svm_clf", LinearSVC(C=10, loss="hinge", random_state=42,max_iter=10000))
])
- svm高斯核
#svm高斯核
def RBFKernelSVC(gamma=1.0):
return Pipeline([
('std_scaler',StandardScaler()),
('svc',SVC(kernel='rbf',gamma=gamma))
])
- 训练函数
def train(files_train,train_site):#训练
'''
files_train:训练文件名的集合
train_site :训练文件在文件夹里的位置
'''
#是否检测到人脸
train_face=[]
#人脸的特征数组
train_feature=[]
#提取训练集的特征数组
get_feature(files_train,train_face,train_feature)
#筛选掉检测不到脸的特征数组
train_x,train_y=filtrate_face(train_face,train_feature,train_site)
svc=PolynomialSVC(degree=1)
svc.fit(train_x,train_y)
return svc#返回训练好的模型
- 测试函数
def test(files_test,test_site,svc):#预测,查看结果集
'''
files_train:训练文件名的集合
train_site :训练文件在文件夹里的位置
'''
#是否检测到人脸
test_face=[]
#人脸的特征数组
test_feature=[]
#提取训练集的特征数组
get_feature(files_test,test_face,test_feature)
#筛选掉检测不到脸的特征数组
test_x,test_y=filtrate_face(test_face,test_feature,test_site)
pre_y=svc.predict(test_x)
ac_rate=0
for i in range(len(pre_y)):
if(pre_y[i]==test_y[i]):
ac_rate+=1
ac=ac_rate/len(pre_y)*100
print("准确率为"+str(ac)+"%")
return ac
- HOG特征提取器
#设置hog的参数
winsize=(64,64)
blocksize=(32,32)
blockstride=(16,16)
cellsize=(8,8)
nbin=9
#定义hog
hog=cv2.HOGDescriptor(winsize,blocksize,blockstride,cellsize,nbin)
#获取文件夹里有哪些文件
files=os.listdir(folder_path+pic_folder)
- 使用10-fold cross validation,数据集中随机的9/10做为训练集:
ac=float(0)
for j in range(10):
site=[i for i in range(4000)]
#训练所用的样本所在的位置
train_site=random.sample(site,3600)
#预测所用样本所在的位置
test_site=[]
for i in range(len(site)):
if site[i] not in train_site:
test_site.append(site[i])
files_train=[]
#训练集,占总数的十分之九
for i in range(len(train_site)):
files_train.append(files[train_site[i]])
#测试集
files_test=[]
for i in range(len(test_site)):
files_test.append(files[test_site[i]])
svc=train(files_train,train_site)
ac=ac+test(files_test,test_site,svc)
save_path='D:/1azanshi/genki4k/save'+str(j)+'(hog).pkl'
joblib.dump(svc,save_path)
ac=ac/10
print("平均准确率为"+str(ac)+"%")
4.2 运行结果
检测结果,结果其实还不错,虽然比用CNN的差了不少,但比高斯核好多了.
- 只检测准确率其实不太行,毕竟样本中的正样本和负样本也不是对半分,下面是检测公式。
4.3 检测函数
4.3.1 代码
def test1(files_test,test_site,svc以上是关于SVM算法应用综合练习--人脸微笑识别的主要内容,如果未能解决你的问题,请参考以下文章
秒懂算法 | 基于主成分分析法随机森林算法和SVM算法的人脸识别问题