数据集简介:
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)))