SVM算法应用综合练习(2)--人脸表情识别

@TOC

流程

  1. 先构建一个HOG特征提取器,到时候图片处理完之后就可以直接提取特征了
  2. 第二步肯定是用opencv来读取数据集,但有些照片是检测不出脸的,可以直接删掉,我是用一个列表来表示能不能检测到脸
  3. 如果对一整张照片进行特征提取的话维数就太多了,不仅影响提取和训练速度,也影响心态,进行了图片截取,我截取的是嘴巴那一部分的
  4. 图片处理好了,就是提取图片的特征值了,提取了特征值之后就是筛掉检测不到脸的图片,后面就是训练和保存图像

代码

# 导入包
import numpy as np
import cv2
import dlib
import random
from sklearn.svm import SVC
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
import os
import joblib
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
import tqdm

folder_path = 'D:/SchoolHomeWork/genki4k/'
label = 'labels.txt'  # 标签文件
pic_folder = 'files/'  # 图片文件路径


# 获得默认的人脸检测器和训练好的人脸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:/SchoolHomeWork/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


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高斯核
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的参数
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)

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:/SchoolHomeWork/genki4k/train/' + str(j) + '(hog).pkl'
    joblib.dump(svc, save_path)
ac = ac / 10
print("平均准确率为" + str(ac) + "%")


def test1(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)
    tp = 0
    tn = 0
    for i in range(len(pre_y)):
        if pre_y[i] == test_y[i] and pre_y[i] == 1:
            tp += 1
        elif pre_y[i] == test_y[i] and pre_y[i] == 0:
            tn += 1
    f1 = 2 * tp / (tp + len(pre_y) - tn)
    print(f1)


svc7 = joblib.load('D:/SchoolHomeWork/genki4k/train/smile9(hog).pkl')
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_test = []
for i in range(len(test_site)):
    files_test.append(files[test_site[i]])
test1(files_test, test_site, svc7)


def smile_detector(img, svc):
    cut_img = cut_face(img, detector, predictor)
    a = []

    if type(cut_img) != int:
        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,))
        a.append(hogdescrip)
        result = svc.predict(a)
        a = np.array(a)
        return result[0]
    else:
        return 2


camera = cv2.VideoCapture(0)  # 打开摄像头
ok = True
flag = 0
# 打开摄像头 参数为输入流,可以为摄像头或视频文件
while ok:
    ok, img = camera.read()
    # 转换成灰度图像
    result = smile_detector(img, svc7)
    if result == 1:
        img = cv2.putText(img, 'smile', (21, 50), cv2.FONT_HERSHEY_COMPLEX, 2.0, (0, 255, 0), 1)
    elif result == 0:
        img = cv2.putText(img, 'no smile', (21, 50), cv2.FONT_HERSHEY_COMPLEX, 2.0, (0, 255, 0), 1)
    else:
        img = cv2.putText(img, 'no face', (21, 50), cv2.FONT_HERSHEY_COMPLEX, 2.0, (0, 255, 0), 1)
    cv2.imshow('video', img)
    k = cv2.waitKey(1)
    if k == 27:  # press 'ESC' to quit
        break
    elif k == 115:
        pic_save_path = 'D:/SchoolHomeWork/genki4k/result/' + str(flag) + '.jpg'
        flag += 1
        cv2.imwrite(pic_save_path, img)
camera.release()
cv2.destroyAllWindows()


结果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值