网上的文章千篇一律
有用的代码万里挑一
毕设做人脸识别,eigenface作为人脸识别基础的算法,一定不能落下。但是我仔细找了许多文章,发现他们都是出自同一篇文章,用的字母没有标识没有注解,语言也是前后不搭,所以很难根据文章复现代码。各种找有用的文章,一周才完成这个eigenface的算法,这里不谈论深入的东西,只看实现的过程。
def readings(img_src):
init_images = []
list_of_dir = os.listdir(img_src)
count = 0
for i in list_of_dir:
if "png" in i and count % 11 == 0:
absolute_path = os.path.join(img_src, i)
img = cv2.imread(absolute_path, 2)
init_images.append(img)
count += 1
return init_images
def flattenedimages(images):
image = np.array(images)
new_image_arr = []
for i in range(15):
new_image_arr.append(image[i].flatten())
return np.array(new_image_arr).T
我们也取竖着的形式,这一步,矩阵维度是: 77760 ∗ 1 77760*1 77760∗1
def mean_matrix(flattened_images):
return np.mean(flattened_images, axis=1).astype(np.uint8)
注意:cv2.imshow()函数只能接受uint8类型的数据矩阵,所以我们在读入数据的时候应该把数据转换成uint8的形式
average_face = mean_matrix(flattened_images) # 3. 计算平均脸
average_face = revive(average_face).astype(np.uint8)
cv2.imshow("asd", average_face)
cv2.waitKey(0)
# 每张人脸减去平均脸,得到列矩阵 77760*15
def submean(image_of_src, average_img):
dimension, numbers = image_of_src.shape[:2]
diffTrain = []
for i in range(numbers):
after_sub = image_of_src[:, i] - average_img
diffTrain.append(after_sub)
return np.array(diffTrain).T
差值矩阵的维度依然是 77760 ∗ 15 77760*15 77760∗15
# 计算特征值和特征向量和协方差矩阵
def get_eigenValue_covEigenVector(diffTrain):
# 1. 计算特征向量,设偏差矩阵为a,则特征向量 temp = a^T * a
temp = np.matmul(diffTrain.T, diffTrain)
# 2. 得到协方差矩阵的特征值和特征向量
eigenValues, eigenVectors = np.linalg.eig(np.mat(temp))
# 3. 得到协方差矩阵的特征向量
covEigenVector = np.matmul(diffTrain, eigenVectors)
return eigenValues, covEigenVector
区别是,我没有让其顺序排列,排列的好处是减少噪声,减少计算量。我没有做这一步(我尝试做这一步后,发现对我的结果没有产生正面影响,结果依然不尽如人意,所以我排除了噪声干扰带来的实验结果不准的问题)。且本来特征脸训练出来应该是很像人脸的,我训练出来却不像。
上图是我随便拿了一张特征脸。看看别人训练出来的:人脸识别经典算法一:特征脸方法(Eigenface)
这一步包含了大量的矩阵运算,我以后有机会会更新矩阵的运算,现在太晚了事情还有很多,待到有缘再相见吧。
# 计算训练集权重
def get_weights_of_train_image(covEigenVectors, after_sub):
# Weight = diffTrain^T * covEigenVectors
weight = np.matmul(after_sub.T, covEigenVectors)
return weight
其实这一步很简单,就是用减去平均脸后的 d i f f T r a i n diffTrain diffTrain,这里是 a f t e r _ s u b after\_sub after_sub的转置乘上面求得的特征脸。 d i f f T r a i n T diffTrain^T diffTrainT的维度是: 15 ∗ 77760 15*77760 15∗77760, a f t e r _ s u b after\_sub after_sub的维度是 77760 ∗ 15 77760*15 77760∗15,因此最后得到的权重是 15 ∗ 15 15*15 15∗15的矩阵,我得到的矩阵如下:
这里只截取了一部分。
# 计算目标脸权重
def get_weights_of_goal_image(covEigenVectors, testface, averageFace):
# 目标脸-平均脸
testface = testface.flatten() - averageFace
# Weight = testface^T * covEigenVectors
weight = np.matmul(testface.T, covEigenVectors)
return weight_train
# 检测人脸与特征脸的欧几里得距离
def detect_face(weight_of_train, weight_of_test):
dimension, number = weight_of_train.shape
distances = []
for i in range(number):
distance = (weight_of_train[i] - weight_of_test) ** 2
distance = np.abs(distance.sum())
distance = distance ** 0.5
distances.append(distance)
return np.array(distances)
import numpy as np
import cv2
import os
def readings(img_src):
init_images = []
list_of_dir = os.listdir(img_src)
count = 0
for i in list_of_dir:
if "png" in i and count % 11 == 0:
absolute_path = os.path.join(img_src, i)
img = cv2.imread(absolute_path, 2)
init_images.append(img)
count += 1
return init_images
# 数据拉平(图像是320*243=77760)
def flattenedimages(images):
image = np.array(images)
new_image_arr = []
for i in range(15):
new_image_arr.append(image[i].flatten())
return np.array(new_image_arr).T
# 计算每一行平均值,形成一个新的行矩阵
def mean_matrix(flattened_images):
return np.mean(flattened_images, axis=1).astype(np.uint8)
# 每张人脸减去平均脸,得到列矩阵 77760*15
def submean(image_of_src, average_img):
dimension, numbers = image_of_src.shape[:2]
diffTrain = []
for i in range(numbers):
after_sub = image_of_src[:, i] - average_img
diffTrain.append(after_sub)
return np.array(diffTrain).T
# 计算特征值和特征向量和协方差矩阵
def get_eigenValue_covEigenVector(diffTrain):
# 1. 计算特征向量,设偏差矩阵为a,则特征向量 temp = a^T * a
temp = np.matmul(diffTrain.T, diffTrain)
# 2. 得到协方差矩阵的特征值和特征向量
eigenValues, eigenVectors = np.linalg.eig(np.mat(temp))
# 3. 得到协方差矩阵的特征向量
covEigenVector = np.matmul(diffTrain, eigenVectors)
return eigenValues, covEigenVector
# 计算训练集权重
def get_weights_of_train_image(covEigenVectors, after_sub):
# Weight = diffTrain^T * covEigenVectors
weight = np.matmul(after_sub.T, covEigenVectors)
return weight
# 计算目标脸权重
def get_weights_of_goal_image(covEigenVectors, testface, averageFace):
# 目标脸-平均脸
testface = testface.flatten() - averageFace
# Weight = testface^T * covEigenVectors
weight = np.matmul(testface.T, covEigenVectors)
return weight_train
# 检测人脸与特征脸的欧几里得距离
def detect_face(weight_of_train, weight_of_test):
dimension, number = weight_of_train.shape
distances = []
for i in range(number):
distance = (weight_of_train[i] - weight_of_test) ** 2
distance = np.abs(distance.sum())
distance = distance ** 0.5
distances.append(distance)
return np.array(distances)
# 将图像还原,得到人脸
def revive(array):
array_ = np.array(array)
img = array_.reshape(243, 320)
return img
img_src = "G:\\face_regconition\\opencv_3\\Eigenface\\yalefaces"
images = readings(img_src) # 1. 读取人脸数据,这里取正常表情的脸
flattened_images = flattenedimages(images) # 2. 数据拉平,维度是77760*15
average_face = mean_matrix(flattened_images) # 3. 计算平均脸
after_sub = submean(flattened_images, average_face) # 4. 训练的每张脸 - 平均脸
eigenValue, covEigenVector = get_eigenValue_covEigenVector(after_sub) # 5. 计算特征值和协方差矩阵
weight_train = get_weights_of_train_image(covEigenVector, after_sub) # 6.计算训练集权重
intended_img_src = "G:\\face_regconition\\opencv_3\\Eigenface\\yalefaces\\subject04_sad_gif.png"
testface = cv2.imread(intended_img_src, 0)
weight_test = get_weights_of_goal_image(covEigenVector, testface, average_face) # 7. 计算目的图片权重
detect = detect_face(weight_train, weight_test)
print(detect)
idx = detect.argsort(-1)
print(idx)
参考:
EigenFace的使用 python
人脸识别经典算法一:特征脸方法(Eigenface)
特征脸(Eigenface)理论基础-PCA(主成分分析法)
人脸识别之特征脸方法(Eigenface)