Day3-基于EigenFace实现人脸识别

  数据集简介:

  Yale人脸数据集由耶鲁大学创建,包含15个人,每个人有不同表情、姿态和光照下的11张人脸图像,共165张图片,每张图片大小为116*98大小。

  关于EigenFace算法基本原理,推荐博客。

  此算法大致分为两大部分,一是训练算法,即用PCA做特征脸;二是检测识别,即对于一张新的人脸,用特征脸进行标示。

import numpy as np
import cv2
import os
# 加载正常脸图像
def loadImageSet(add):
    face_all = np.zeros((15, 98*116))
    j = 0
    # 1 读取人脸图像
    image_list = os.listdir(add) # 返回指定文件夹下的文件名或者文件夹列表
    image_new = np.sort(image_list) # 对文件名进行排序
    # 2 遍历文件夹下人脸图像,找出所有的正常脸
    for i in image_new:
        if i.split('.')[1] == 'normal': # 加载无表情的正常脸
            try:
                img = cv2.imread(add + i, 0) # 要加载的正常脸图像地址
            except:
                print('load %s failed' % i)
            face_all[j, :] = np.array(img).flatten() # 将图像展平
            j += 1
    # 2 返回图像组,大小为 15*11368维度
    return face_all

# 获取特征脸
def ReconginitionVector(image_train, selecthr = 0.8):
    # 1 加载所有正常脸图像
    FaceNP = loadImageSet(image_train).T  ## 图像转置 11368 * 15
    # 2 计算平均脸(大众脸) 11368 * 1
    avgImg = np.mean(FaceNP, axis = 1)  ## axis=1,表示按列进行均值计算,输出为1*11368
    # 3 人脸 减去 均值脸, 得偏差值 11368 * 15
    diffTrain = FaceNP - avgImg.reshape(-1, 1)
    # 4 使用numpy函数计算人脸特征值、特征向量 15
    eigvals, eigVects = np.linalg.eig(np.matmul(diffTrain.T, diffTrain))
    eigSortIndex = np.argsort(-eigvals) # 从小到大排序后的数组索引
    # 5 判断是否为特征脸
    for i in range(np.shape(FaceNP)[1]):
        # 如果满足 特征值大于固定阈值,则选择前N组为特征脸
        if (eigvals[eigSortIndex[:i]] / eigvals.sum()).sum() >= selecthr:
            eigSortIndex = eigSortIndex[:i]
            break
    # 6 求协方差矩阵的特征向量
    covVects = np.matmul(diffTrain, eigVects[:, eigSortIndex])  # covVects是协方差矩阵特征向量
    # 保存特征脸
    for i in range(len(eigSortIndex)):
        cv2.imwrite('img_' + str(i) + '.jpg', covVects[ : , i].T.reshape(116, 98))
    # 7 返回值:avgImg 是均值图像1*11368,covVects是协方差矩阵的特征向量,diffTrain是偏差矩阵
    return avgImg, covVects, diffTrain


# 判断图像属于哪个一类
def judgeFace(judgeImg, FaceVector, avgImg, diffTrain):
    """
    :param judgeImg: 待分类的图像
    :param FaceVector: 特征脸图像
    :param avgImg: 平均脸
    :param diffTrain: 偏差矩阵
    :return: 返回待分类人脸类别
    """
    diff = judgeImg.T - avgImg
    weiVec = np.matmul(FaceVector.T, diff)
    res = 0
    resVal = np.inf
    for i in range(15):
        TrainVec = np.matmul(FaceVector.T, diffTrain[:, i])

        if (np.array(weiVec - TrainVec) ** 2).sum() < resVal:
            res = i
            resVal = (np.array(weiVec - TrainVec) ** 2).sum()

    return int(res) + 1


if __name__ == '__main__':
    # 1 下载的数据集,存放的文件夹路径
    image_path = "./unpadded/"
    # 2 特征脸识别
    avgImg, FaceVector, diffTrain = ReconginitionVector(image_path, selecthr = 0.8)
    # 3 保存平均脸
    img = avgImg.reshape(116, 98)
    cv2.imwrite('avgImg.jpg', img)
    # 所有人员集合
    nameList = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15']
    # 所有表情集合
    characteristic = ['centerlight', 'glasses', 'happy', 'leftlight','normal', 'noglasses', 'rightlight', 'sad', 'sleepy',
                      'surprised', 'wink']
    # 4 求出每个表情的正确率
    for c in characteristic: # 表情
        count = 0
        for i in range(len(nameList)): # 人员
            # 这里的loadname就是我们要识别的未知人脸图,我们通过15张未知人脸找出的对应训练人脸进行对比来求出正确率
            loadname = image_path + "subject"+ nameList[i] + '.' + c + '.pgm'
            judgeImg = cv2.imread(loadname, 0)

            if judgeFace(judgeImg.flatten(), FaceVector, avgImg, diffTrain) == int(nameList[i]):
                count += 1
        print('accuracy of %s is %f' % (c, float(count) / len(nameList)))
    # 5 求出每个人的正确率
    for c in nameList:
        count = 0
        for i in range(len(characteristic)):
            if characteristic[i] != 'normal':
                loadname = image_path + "subject" + c + '.' + characteristic[i] + '.pgm'
                judgeImg = cv2.imread(loadname, 0)

                if judgeFace(judgeImg.flatten(), FaceVector, avgImg, diffTrain) == int(c):
                    count += 1
        print('accuracy of %s is %f' % (c, float(count) / len(characteristic)))

 

你可能感兴趣的:(人脸检测识别基础,人脸识别)