模式识别实验:基于主成分分析(PCA)的人脸识别
前言
本文使用Python实现了PCA算法,并使用ORL人脸数据集进行了测试并输出特征脸,简单实现了人脸识别的功能。
1. 准备
ORL人脸数据集共包含40个不同人的400张图像,是在1992年4月至1994年4月期间由英国剑桥的Olivetti研究实验室创建。此数据集包含40个类,每个类含10张图片。所有的图像是以PGM格式存储,灰度图,图像大小为 92 x 112像素。
对于每个类,我们选择前7张图片用于训练,后3张图片用于测试。我们将图像缩放至原来的0.5倍,以加快训练速度。最后选择100个特征向量进行降维。
import os
import cv2
import numpy as np
from typing import Union, LiteralString
import matplotlib.pyplot as plt
%matplotlib inline
scaled = 0.5 # 图像缩放至原来的scaled倍
train_num = 7 # 7张用于训练
img_num = 10 # 总共10张图片
num_k = 100 # 选择100个特征
save_path = './ORL_eigenfaces'
dataset_path = '../dataset/ORL/att_faces/'
cov_matrix_path = './PCA_ORL.npy'
2. 数据集处理
将每个类的前7张图片使用img2np转为一维向量,作为训练集。并计算每个类前7张图片的平均特征向量,用于后面的对比。
# 图像转为一维向量
def img2np(img_path: Union[str, LiteralString], scaled: float = 1.) -> np.ndarray:
img = cv2.imread(img_path)
h, w = img.shape[0], img.shape[1]
img = cv2.resize(img, (int(h * scaled), int(w * scaled)))
if img.shape[-1] > 1:
img = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
return np.array(img).flatten()
class_names = os.listdir(dataset_path)
print(f'数据集总共有 {len(class_names)} 个类')
# 列表示特征值,行表示图像
samples_data = []
avg_feature = [] # 每个类的平均特征
for class_name in class_names:
class_path = os.path.join(dataset_path, class_name)
img_names = os.listdir(class_path)
class_feature = [] # 计算每个类前train_num的平均特征
for img_name in img_names[:train_num]: # 取前七张参与训练
img_data = img2np(os.path.join(class_path,img_name), scaled=scaled)
samples_data.append(img_data)
class_feature.append(img_data)
avg_feature.append(np.array(class_feature).mean(axis=0))
samples_data = np.array(samples_data)
avg_feature = np.array(avg_feature)
print(f'数据集特征矩阵形状: {samples_data.shape},平均特征矩阵形状:{avg_feature.shape}')
数据集总共有 40 个类
数据集特征矩阵形状: (280, 2576),平均特征矩阵形状:(40, 2576)
3. PCA降维
PCA计算时间较长,因此建议先对图像进行缩放,并保存降维后的特征矩阵,方便后续调用。
# PCA算法保留前k个特征向量
def pca(X: np.ndarray, k: int) -> np.ndarray:
# 计算每个特征均值
mean = np.mean(X, axis=0)
# 数据标准化
norm_X = X - mean
# 计算协方差矩阵
cov_matrix = np.cov(norm_X, rowvar=False)
# 计算特征值与特征向量
eig_val, eig_vec = np.linalg.eig(cov_matrix)
abs_eig_vec = np.abs(eig_val)
# 按照特征值的绝对值大小增序排序
sorted_Index = np.argsort(abs_eig_vec)
# 选择前k个特征值对应的特征向量
selected_vectors = eig_vec[:, sorted_Index[-k :]]
# 低维投影
return selected_vectors
if os.path.exists(cov_matrix_path):
pca_vectors = np.load(cov_matrix_path)
else:
pca_vectors = pca(samples_data, num_k) # 选择100个特征向量
np.save(cov_matrix_path, pca_vectors) # 训练时间较长,可以保存方便调用
print(f'PCA降维后的特征矩阵形状: {pca_vectors.shape}')
PCA降维后的特征矩阵形状: (2576, 100)
4. 测试
假设有C个类,每个图像的特征值数为N,降维后选取的特征向量数为K。
首先对类的平均特征矩阵进行降维,降维后的矩阵形状为(C x K)。
测试时:
- 对每张测试图片进行降维:图像特征(1 x N)与PCA降维特征向量(N x K)相乘;
- 对第一步得到的结果与平均特征矩阵的每一行(每一行大小为1 x K)进行余弦相似度比较得到C个数;
- 选择C个数中最大的下标,就是预测的类别。
pca_avg_feature = np.dot(avg_feature, pca_vectors) # 进行降维
print(f'PCA降维后的平均特征矩阵形状: {pca_avg_feature.shape}')
PCA降维后的平均特征矩阵形状: (40, 100)
# 计算余弦相似度
def cosine_similarity(vec1: np.ndarray, vec2: np.ndarray):
# 向量点乘
dot_product = np.dot(vec1, vec2)
# 计算L2范数
magnitude1 = np.linalg.norm(vec1)
magnitude2 = np.linalg.norm(vec2)
# 计算余弦相似度
return dot_product / (magnitude1 * magnitude2)
test_res = []
correct = 0
wrong = 0
for i, class_name in enumerate(class_names):
class_path = os.path.join(dataset_path, class_name)
img_names = os.listdir(class_path)
true_label = i
for img_name in img_names[train_num: img_num]:
img_data = img2np(os.path.join(class_path, img_name), scaled=scaled)
predict_img = np.dot(img_data, pca_vectors)
similarity = []
for j in pca_avg_feature:
similarity.append(cosine_similarity(j, predict_img))
predict_label = np.argmax(similarity)
if true_label == predict_label:
correct += 1
else:
wrong += 1
test_res.append((true_label, predict_label))
accuracy = correct / (correct + wrong)
print(f'Total samples: {correct + wrong}, correct: {correct}, wrong: {wrong}, accuracy: {accuracy:.4f}')
Total samples: 120, correct: 111, wrong: 9, accuracy: 0.9250
5. 结果展示
将特征向量保存为特征脸并输出。此处注意下,缩放后的图像大小为56 x 46,但保存的特征脸大小为 46 x 56。
# 保存前k个特征向量的特征脸
def save_eigenfaces(eigenvectors: np.ndarray,
k: int,
img_size: tuple[int, int], # (h, w)
path: Union[str, LiteralString]) -> bool:
if os.path.exists(path) is False:
os.mkdir(path) # 创建保存路径文件夹
for i in range(k):
eigenfaces = np.real(eigenvectors[:, i])
# 对特征向量进行归一化,投影到0-255的灰度空间
norm_eigenfaces = ((eigenfaces - np.min(eigenfaces)) /
(np.max(eigenfaces) - np.min(eigenfaces)) * 255)
norm_eigenface_uint8 = norm_eigenfaces.astype(np.uint8)
shaped_eigenface = norm_eigenface_uint8.reshape(img_size)
cv2.imwrite(os.path.join(path, f'eigenfaces{i}.png'), shaped_eigenface)
return True
save_eigenfaces(pca_vectors, 100, (46, 56), save_path) # 原大小为112 x 92,缩放后为56 x 46
plt.figure(figsize=(8, 8))
for i in range(16):
plt.subplot(4,4,i+1)
plt.imshow(cv2.imread(os.path.join(save_path, f'eigenfaces{i}.png')))
plt.title(f'eigenfaces{i}')
plt.xticks([])
plt.yticks([])
plt.show()

6. 总结
PCA可以实现简单的人脸识别。
环境配置:
matplotlib==3.7.2
numpy==1.25.2
opencv_python==4.8.1.78
模式识别实验:基于主成分分析(PCA)的人脸识别的更多相关文章
- 基于PCA的人脸识别步骤
代码下载:基于PCA(主成分分析)的人脸识别 人脸识别是一个有监督学习过程,首先利用训练集构造一个人脸模型,然后将测试集与训练集进行匹配,找到与之对应的训练集头像.最容易的方式是直接利用欧式距离计算测 ...
- 基于Face-Recognition的计算机人脸识别安全认证程序
20202411 2020-2021-2 <Python程序设计>实验四报告 基于Face-Recognition的计算机人脸识别安全认证程序 课程:<Python程序设计> ...
- 基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【一】如何配置caffe属性表
前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...
- 基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【三】VGG网络进行特征提取
前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...
- 基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【二】人脸预处理
前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...
- 基于深度学习的人脸识别系统系列(Caffe+OpenCV+Dlib)——【四】使用CUBLAS加速计算人脸向量的余弦距离
前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...
- 基于卷积神经网络的人脸识别项目_使用Tensorflow-gpu+dilib+sklearn
https://www.cnblogs.com/31415926535x/p/11001669.html 基于卷积神经网络的人脸识别项目_使用Tensorflow-gpu+dilib+sklearn ...
- 基于Opencv快速实现人脸识别(完整版)
无耻收藏网页链接: 基于OpenCV快速实现人脸识别:https://blog.csdn.net/beyond9305/article/details/92844258 基于Opencv快速实现人脸识 ...
- 【笔记】特征脸(PCA在人脸识别领域的应用)
人脸识别与特征脸(简单介绍) 什么是特征脸 特征脸(Eigenface)是指用于机器视觉领域中的人脸识别问题的一组特征向量,该方法被认为是第一种有效的人脸识别方法. PCA的具体实现思想见 [笔记]主 ...
- 基于Emgu CV+百度人脸识别,实现视频动态 人脸抓取与识别
背景 目前AI 处于风口浪尖,作为 公司的CTO,也作为自己的技术专研,开始了AI之旅,在朋友圈中也咨询 一些大牛对于AI 机器学习框架的看法,目前自己的研究方向主要开源的 AI 库,如:Emgu C ...
随机推荐
- Android 3分钟带你入门开发测试
作者:Zhu Yifei 作为一名合格的开发人员,基本的开发测试能力必不可少,开发测试分单元测试和UI测试,通过开发测试可以减少开发人员自测时间,提升开发质量.本篇文章可以帮助初级开发人员快速了解开发 ...
- 基于阿里云Serverless函数计算开发的疫情数据统计推送机器人
一.Serverless函数计算 什么是Serverless? 在<Serverless Architectures>中对 Serverless 是这样子定义的: Serverless w ...
- 打包报错,提示UglifyJs Unexpected token: keyword «const»
https://blog.csdn.net/weixin_43473561/article/details/102816018 原因:ugluifyjs当前版本不符合项目预期(可能不能解析es6) 解 ...
- pmp考试巩固知识点
1.冲刺评审会是需要相关的干系人参加的,在冲刺评审会上干系人可以审查并澄清角色.责任和管理模式2.采购中的争议,往往找合同和SOW,SOW是对需要采购的详细范围的描述,与供应商在可交付成果方面有争议时 ...
- spring,springBoot配置类型转化器Converter以及FastJsonHttpMessageConverter,StringHttpMessageConverter 使用
转载请注明出处: https://i.cnblogs.com/posts/edit;postId=14045507 spring,spring boot 等框架项目通过@RequestBody,@Re ...
- 【MicroPython】 mp对象和 c 类型的转换
[来源]https://www.eemaker.com/micropython-mp-toc.html
- 使用Java分析器优化代码性能,解决OOM问题
有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 背景 最近我一直在做性能优化,对一个单机应用做性能优化.主要是 ...
- [转帖]如何不耍流氓的做运维之-SHELL脚本
https://www.cnblogs.com/luoahong/articles/8504691.html 前言 大家都是文明人,尤其是做运维的,那叫一个斯文啊.怎么能耍流氓呢?赶紧看看,编写SHE ...
- [转帖]TNS-12535 TNS-00505的处理方法
硬件说明: 操作系统版本:ORACLE LINUX 6.3 64位 数据库版本:11.2.0.3 64位 问题说明: 在检查数据库的alert日志的时候,发现大量的12170和TNS-12535 ...
- [转帖]043、TiDB特性_缓存表和分区表
针对于优化器在索引存在时依然使⽤全表扫描的情况下,使⽤缓存表和分区表是提升查询性能的有效⼿段. 缓存表 缓存表是将表的内容完全缓存到 TiDB Server 的内存中 表的数据量不⼤,⼏乎不更改 读取 ...