计算机视觉之PCA和特征脸

本文介绍了PCA(主成分分析)在计算机视觉中的应用,包括手写数字和人脸图像的降维与可视化。通过scikit-learn库展示了PCA如何将高维数据(如64维的手写数字和4096维的人脸图像)转换为低维表示,同时保留大部分方差。PCA的两个主要组件(特征脸)被用来表示数据集的关键特征,并用于图像重建,结果显示重建后的图像与原始图像高度相似。
摘要由CSDN通过智能技术生成

计算机视觉之PCA和特征脸

主成分分析(PCA)是一种统计/非监督机器学习方法,它使用一个正交变换将一组可能相关的变量的观测值转化为一组线性不相关的变量的值(称为主成分),从而在数据集中发现最大方向的方差(沿着主成分)。这可以用于(线性)降维(只有几个突出的主成分在大多数情况下捕获数据集中的几乎所有方差)和具有多个维度的数据集的可视化(在二维空间中)。PCA 的一个应用是特征脸,找到一组可以(从理论上)表示任意脸(作为这些特征脸的线性组合)的特征脸。

1.用 PCA 降维及可视化

我们将使用 scikit-learn 的数字数据集,其中包含 1797 张手写数字图像(每张图像大小为 8×8)。每一行表示数据矩阵中的一幅图像。用下面的代码加载并显示数据集中的前 25 位数字:

import numpy as np 
import matplotlib.pylab as plt 
from  matplotlib  import pylab
from sklearn.datasets import load_digits 
from sklearn.preprocessing import StandardScaler 
from sklearn.decomposition import PCA 
from sklearn.pipeline import Pipeline 
digits = load_digits() 
#print(digits.keys()) 
print(digits.data.shape) 
j = 1 
np.random.seed(2) 
fig = plt.figure(figsize=(3,3)) 
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05,wspace=0.05) 
#从数组中随机抽取元素
for i in np.random.choice(digits.data.shape[0], 25): 
     plt.subplot(5,5,j), plt.imshow(np.reshape(digits.data[i,:], (8,8)),cmap='binary'), plt.axis('off') 
     j += 1 
plt.show() 

运行上述代码,输出数据集中的前 25 位手写数字,如图:
在这里插入图片描述

2.二维投影和可视化

从加载的数据集可以看出,它是一个 64 维的数据集。现在,首先利用scikit-learn 的 PCA()函数来找到这个数据集的两个主成分并将数据集沿着两个维度进行投影;其次利用 matplotlib 和表示图像(数字)的每个数据点,对投影数据进行散点绘图,数字标签用一种独特的颜色表示,如下面的代码所示:

plt.show() 
pca_digits=PCA(2) 
digits.data_proj = pca_digits.fit_transform(digits.data) 
print(np.sum(pca_digits.explained_variance_ratio_))
# 0.28509364823696987 
plt.figure(figsize=(15,10)) 
plt.scatter(digits.data_proj[:, 0], digits.data_proj[:, 1], lw=0.25, c=digits.target, edgecolor='k', s=100, cmap=plt.cm.get_cmap('cubehelix',10)) 
plt.xlabel('PC1', size=20), plt.ylabel('PC2', size=20), plt.title('2D Projection of handwritten digits with PCA', size=25) 
plt.colorbar(ticks=range(10), label='digit value') 
plt.clim(-0.5, 9.5) 

在这里插入图片描述

3.基于 PCA 的特征脸

加载 scikit-learn 包的 olivetti 人脸数据集,其中包含 400 张人脸图像,每
张图像大小为 64×64。如下代码显示了数据集中的一些随机人脸:

#人脸数据
from sklearn.datasets import fetch_olivetti_faces 
faces = fetch_olivetti_faces().data 
print(faces.shape) # there are 400 faces each of them is of 64x64=4096 pixels 
fig = plt.figure(figsize=(5,5)) 
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05) 
# plot 25 random faces 
j = 1 
np.random.seed(0) 
for i in np.random.choice(range(faces.shape[0]), 25): 
     ax = fig.add_subplot(5, 5, j, xticks=[], yticks=[]) 
     ax.imshow(np.reshape(faces[i,:],(64,64)), cmap=plt.cm.bone,interpolation='nearest')
     j += 1 
plt.show() 

在这里插入图片描述运行上述代码,输出从数据集中随机选取的 25 张人脸图像接下来,对数据集进行预处理,在对图像应用 PCA 之前先执行 z-score 归一化(从所有人脸中减去均值人脸,然后除以标准差),这是必要的步骤;然后,使用 PCA()计算主成分,只选取 64 个(而不是 4096 个)主成分,并将数据集投影到 PC 方向上,如下面的代码所示,而且通过选择越来越多的主成分来可视化图像数据集的方差。

from sklearn.preprocessing import StandardScaler 
from sklearn.decomposition import PCA 
from sklearn.pipeline import Pipeline 
n_comp =64 
pipeline = Pipeline([('scaling', StandardScaler()), ('pca',PCA(n_components=n_comp))]) 
faces_proj = pipeline.fit_transform(faces) 
print(faces_proj.shape) 
# (400, 64) 
mean_face = np.reshape(pipeline.named_steps['scaling'].mean_, (64,64)) 
sd_face = np.reshape(np.sqrt(pipeline.named_steps['scaling'].var_),(64,64)) 
pylab.figure(figsize=(8, 6)) 
pylab.plot(np.cumsum(pipeline.named_steps['pca'].explained_variance_ratio_) , linewidth=2) 
pylab.grid(), pylab.axis('tight'), pylab.xlabel('n_components'), 
pylab.ylabel('cumulative explained_variance_ratio_') 
pylab.show() 
pylab.figure(figsize=(10,5)) 
pylab.subplot(121), pylab.imshow(mean_face, cmap=pylab.cm.bone), 
pylab.axis('off'), pylab.title('Mean face') 
pylab.subplot(122), pylab.imshow(sd_face, cmap=pylab.cm.bone), 
pylab.axis('off'), pylab.title('SD face') 
pylab.show() 

在这里插入图片描述运行上述代码,输出结果如图所示。可以看到,大约 90%的方差仅由前 64 个主成分所解释。从数据集中计算得到的人脸图像的均值和标准差.
在这里插入图片描述

(1)特征脸

在主成分分析的基础上,计算得到的两 PC 方向相互正交,每个 PC 包
含 4096 个像素,并且可以重建成 64×64 像素的图像。称这些主成分为特征脸(因为它们也是特征向量)。可以看出,特征脸代表了人脸的某些属性。如下代码用于显示一些计算出来的特征脸:

fig = plt.figure(figsize=(5,2)) 
fig.subplots_adjust(left=0, right=2, bottom=0, top=5, hspace=0.07,wspace=0.005) 
# plot the first 10 eigenfaces 
for i in range(25): 
     ax = fig.add_subplot(5, 5, i+1, xticks=[], yticks=[]) 
     ax.imshow(np.reshape(pipeline.named_steps['pca'].components_[i,:],(64,64)), cmap=plt.cm.bone, interpolation='nearest') 
     plt.savefig("C:/Users/zhuyupeng/Desktop/新建文件夹/hsdh.png",bbox_inches = 'tight')

在这里插入图片描述
运行上述代码,输出前 25 张特征脸,如图所示

(2)重建。

如下代码演示了如何将每张人脸近似地表示成这 64 张主要特征脸的线性
组合。使用 scikit-learn 中的 inverse_transform()函数变换回到原空间,但是只基于这 64 张主要特征脸,而抛弃所有其他特征脸。

#重建
# face reconstruction 
faces_inv_proj = pipeline.named_steps['pca'].inverse_transform(faces_proj) 
#reshaping as 400 images of 64x64 dimension 
fig = plt.figure(figsize=(5,5)) 
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05,wspace=0.05) 
# plot the faces, each image is 64 by 64 dimension but 8x8 pixels 
j = 1 
np.random.seed(0) 
for i in np.random.choice(range(faces.shape[0]), 25): 
     ax = fig.add_subplot(5, 5, j, xticks=[], yticks=[]) 
     ax.imshow(mean_face + sd_face*np.reshape(faces_inv_proj,(400,64,64))[i,:], cmap=plt.cm.bone, interpolation='nearest') 
     j += 1

在这里插入图片描述
运行上述代码,从 64 张特征脸中随机选择 25 张重建的人脸图像,如图 上 所示。可以看到,它们看起来很像原始的人脸(没有很多明显的错误)。如下代码有助于更近距离地观察原始人脸,并将其与重建后的人脸进行对比,代码的输出结果如下图所示。可以看到,重建后的人脸与原始人脸近似,但存在某种程度的失真。

orig_face = np.reshape(faces[0,:], (64,64)) 
reconst_face =np.reshape(faces_proj[0,:]@pipeline.named_steps['pca'].components_, (64,64))
reconst_face = mean_face + sd_face*reconst_face 
plt.figure(figsize=(10,5)) 
plt.subplot(121), plt.imshow(orig_face, cmap=plt.cm.bone, interpolation='nearest'), plt.axis('off'), plt.title('original', size=20) 
plt.subplot(122), plt.imshow(reconst_face, cmap=plt.cm.bone, interpolation='nearest'), plt.axis('off'), plt.title('reconstructed', size=20) 
plt.show() 

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值