基于opencv的pca人脸识别实现

orl人脸样本库

这里用到的ORL人脸库(Olivetti Research Laboratory人脸数据库),诞生于英国剑桥Olivetti实验室。

ORL人脸数据库由该实验室从1992年4月到1994年4月期间拍摄的一系列人脸图像组成,共有40个不同年龄、不同性别和不同种族的对象。每个人10幅图像共计400幅灰度图像组成,图像尺寸是92×112,图像背景为黑色。其中人脸部分表情和细节均有变化,例如笑与不笑、眼睛睁着或闭着,戴或不戴眼镜等,人脸姿态也有变化,其深度旋转和平面旋转可达20度,人脸尺寸也有最多10%的变化。该库是目前使用最广泛的标准人脸数据库,特别是刚从事人脸识别研究的学生和初学者,研究ORL人脸库是个很好的开始。
人脸库下载:https://github.com/Gaoshiguo/PCA-Principal-Components-Analysis
下载压缩包orl.rar,获得bmp格式的人脸灰度图

自制人脸样本库

代码实现:

# 导入所需模块
import matplotlib.pyplot as plt
import numpy as np
import os
import cv2
# plt显示彩色图片
def plt_show0(img):
    b,g,r = cv2.split(img)
    img = cv2.merge([r, g, b])
    plt.axis('off')
    plt.imshow(img)
    plt.show()

# 加载人脸检测模型
face_engine = cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')
img = cv2.imread(r'.\test.png')
plt_show0(img)

# 复制图像灰度处理
img_ = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 检测人脸获取人脸区域
faces = face_engine.detectMultiScale(gray)
# 将检测出的人脸可视化
for(x, y, w, h) in faces:
    cv2.rectangle(img_, (x, y), (x + w, y + h), (0, 0, 255), 3)
    plt_show0(img_)
    face = img[y:y + w, x:x + h]
    plt_show0(face)
output:

在这里插入图片描述

这里使用的是opencv自带的人脸识别模型,生成的图片分辨率是640480,不能直接使用pca降维,需要对图片进行裁剪缩放,灰度处理。使用photoshop或者python均可,图像大小调整为92112即可

PCA算法

算法原理

算法是利用K-L变换来进行特征提取的。K-L变换是满足上述原则的一 种数据压缩方法 , 它的特征提取的基本原理是 在测量空间中找出一组 个正交矢量, 要求这组矢量能最大的表示出数据的方差然后将原模式矢量从维空间投影到这组正交矢量构成的维子空间, 则投影系数就是构成原模式的特征矢量, 且完成了维数的压缩。
设训练样本为x=(x1,x2,…,x200)T, 特征提取的具体步骤如下:
1、计算训练图片的平均脸:ψ=average(xi)
2、计算每一张人脸图片与平均脸的差值di=xi-ψ
3、构建协方差矩阵C=1/200*ATA
4、求矩阵V=ATA的特征值λ及其对应的正交归一化特征矢量vi
5、选取前p(p<<200)最大特征值及其对应的特征向量
6、求C的正交归一化特征向量
7、将每一幅人脸与平均脸的差值矢量投影到“特征脸”空间

1、利用训练图像数据构建特征脸空间
#导入所需模块
import matplotlib.pyplot as plt
import numpy as np
import os
import cv2
#plt显示灰度图片
defplt_show(img):
plt.imshow(img,cmap='gray')
plt.show()
#读取一个文件夹下的所有图片
defread_directory(directory_name):
faces_addr=[]
forfilenameinos.listdir(directory_name):
faces_addr.append(directory_name+"/"+filename)
returnfaces_addr
#读取所有人脸文件夹,保存图像地址在列表中
faces=[]
foriinrange(1,41):#如果没有自制人脸库,需要将此处改为1:40
faces_addr=read_directory('.\TrainDatabase\s'+str(i))
foraddrinfaces_addr:
faces.append(addr)
#读取图片数据,生成列表标签
images=[]
labels=[]
forindex,faceinenumerate(faces):
image=cv2.imread(face,0)
images.append(image)
labels.append(int(index/10+1))
print(len(labels))
print(len(images))
print(type(images[0]))
print(labels)
output:

410
410
<class ‘numpy.ndarray’>
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41]

2、训练阶段,主要是将训练图像投影到特征脸子空间上
#图像数据转换特征矩阵
image_data=[]
forimageinimages:
data=image.flatten()
image_data.append(data)
print(image_data[0].shape)
OUT:

(10304,)

#转换为numpy数组
X=np.array(image_data)
y=np.array(labels)
print(type(X))
print(X.shape)

#导入sklearn的pca模块
fromsklearn.decompositionimportPCA
fromsklearn.model_selectionimporttrain_test_split
#画出特征矩阵
importpandasaspd
data=pd.DataFrame(X)
data.head()
dtype=object
#划分数据集
x_train,x_test,y_train,y_test=train_test_split(X,y,test_size=0.2)
#训练PCA模型
pca=PCA(n_components=100)
pca.fit(x_train)
#返回测试集和训练集降维后的数据集
x_train_pca=pca.transform(x_train)
x_test_pca=pca.transform(x_test)
print(x_train_pca.shape)
print(x_test_pca.shape)
OUT:

(328, 100)
(82, 100)

V=pca.components_
V.shape
#100个特征脸
#创建画布和子图对象
fig,axes=plt.subplots(10,10
,figsize=(15,15)
,subplot_kw={"xticks":[],"yticks":[]}#不要显示坐标轴
)
#填充图像
fori,axinenumerate(axes.flat):
ax.imshow(V[i,:].reshape(112,92),cmap="gray")#选择色彩的模式
pca.explained_variance_ratio_
print(pca.explained_variance_ratio_)
pca.explained_variance_ratio_.sum()
output:

在这里插入图片描述

explained_variance_ratio=[]
foriinrange(1,151):
pca=PCA(n_components=i).fit(x_train)
explained_variance_ratio.append(pca.explained_variance_ratio_.sum())
plt.plot(range(1,151),explained_variance_ratio)
plt.show()
output:

array([0.16754406, 0.11712118, 0.08050592, 0.05800583, 0.04899411, 0.03236304, 0.02552568, 0.02246334, 0.02105942, 0.01869678, 0.01492577, 0.01452819, 0.01195689, 0.01106418, 0.01061136, 0.00920361, 0.00893044, 0.00841665, 0.00815548, 0.00745415, 0.00684847, 0.00674609, 0.00641437, 0.00555017, 0.00533678, 0.00511044, 0.00498169, 0.00493545, 0.00477643, 0.0046901 , 0.00452947, 0.00443995, 0.00424948, 0.00415627, 0.00402244, 0.00391703, 0.00380438, 0.00365518, 0.00347555, 0.00338822, 0.00325 , 0.00306806, 0.00305956, 0.00297671, 0.00286721, 0.00281228, 0.00272433, 0.00266031, 0.00257338, 0.00251557, 0.00247235, 0.00243605, 0.00236254, 0.00232992, 0.00225821, 0.00221418, 0.00217406, 0.00213639, 0.00203163, 0.00199645, 0.00194659, 0.00193678, 0.00187899, 0.00186114, 0.00181597, 0.00178071, 0.0017298 , 0.00171467, 0.00166234, 0.00163148, 0.00160447, 0.00157375, 0.00155019, 0.00154325, 0.00152017, 0.00149426, 0.00147426, 0.00145617, 0.00143343, 0.00140277, 0.00138425, 0.00135825, 0.00134036, 0.00133259, 0.00129024, 0.00126753, 0.00124071, 0.00123078, 0.00121395, 0.00119294, 0.00116697, 0.00115547, 0.00111406, 0.00111104, 0.00109964, 0.00107608, 0.00106702, 0.00105275, 0.00102797, 0.00100745])
0.9002145083699277

array里的这些值代表这些特征量对原图的贡献,最后这里300个特征量的贡献占到总10000多维度的90%

3、识别阶段,将待识别图像也投影到特征脸子空间上,并且与投影后的训练图像相比较,得出识别结果。
#模型创建与训练
model=cv2.face.EigenFaceRecognizer_create()
model.train(x_train,y_train)
#预测
res=model.predict(x_test[0])
print(res)
#测试数据集的准确率
ress=[]
true=0
foriinrange(len(y_test)):
res=model.predict(x_test[i])
#print(res[0])
ify_test[i]==res[0]:
true=true+1
else:
print(i)

print('测试集识别准确率:%.2f'%(true/len(y_test)))
output:

(17, 3574.1839755765554)
0
测试集识别准确率:0.99

#降维
pca=PCA(n_components=100)
pca.fit(X)
X=pca.transform(X)
#将所有数据都用作训练集
#模型创建与训练
model=cv2.face.EigenFaceRecognizer_create()
model.train(X,y)
#plt显示彩色图片
defplt_show0(img):
b,g,r=cv2.split(img)
img=cv2.merge([r,g,b])
plt.imshow(img)
plt.show()
#输入图片识别
img=cv2.imread('./att_faces/test.jpg')
plt_show0(img)
print(img.shape)

#灰度处理
img=cv2.imread('./att_faces/test.jpg',0)
plt_show(img)
imgs=[]
imgs.append(img)
#特征矩阵
image_data=[]
forimginimgs:
data=img.flatten()
image_data.append(data)
test=np.array(image_data)
test.shape

# 用训练好的pca模型给图片降维
test = pca.transform(test)
test[0].shape
res = model.predict(test)
res
print('人脸识别结果:',res[0])
output:

(41, 4308.711798033283)
人脸识别结果: 41

参考资料:
https://www.cnblogs.com/zq98/p/12844549.html
视频讲解

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值