eigenface实现

eigenface算法步骤 特征脸 TIPs:

  1. M就是图片一共多少张;N维向量指图片flatten成一位向量的维数,即N = 图片高*宽
  2. 每张图片flatten成列向量,按列排,每一行就是每张图片在某一像素点灰度值/RGB值
  3. 零均值化后的矩阵维度是(高*宽,N),如果直接用要用协方差矩阵降维,cov_mat维度(高*宽,高*宽)
  4. 不是对零均值化后的矩阵求特征值和特征向量,是对中心化矩阵的协方差矩阵cov_mat求eig

code:
<pre><code> eigenface.py

import numpy as np from numpy import linalg as la

def eigenface(imgs):

'''
:param imgs: imgs的维度为MxHxW。即有M张图片,每一张高为H宽为W。
:return: a, b
a: 特征值。 为一维向量。
b: 特征向量。 为二维向量, b[:,i]是特征值a[i]对应的特征向量.
'''

imgs_2d = []
for i in range(0,400):
    img_temp = imgs[i,:,:].flatten()   #把每张图片flatten,按列放到矩阵imgs_2d里
    imgs_2d.append(img_temp)
imgs_2d = np.mat(imgs_2d).T
imgs_mean = np.mean(imgs_2d,axis=1)   #对每行求mean,相当于对每个像素点都取mean
imgs_diff = np.mat(imgs_2d) - np.mat(imgs_mean)  #对每个像素点零均值化
#a,b = la.eig(imgs_diff.T*imgs_diff)   #不是求样本中心化矩阵imgs_diff的特征值,而是求imgs_diff的协方差矩阵的特征值
cov_mat = imgs_diff*imgs_diff.T/400   #求协方差矩阵
a,b = la.eig(cov_mat)
b = np.asarray(b)   #最好不要用mat格式,不然会数值溢出
return a, b

</code></pre>

<pre><code> main.py
from future import division from future import print_function

import os import numpy as np from pathlib import Path from PIL import Image import matplotlib.pyplot as plt import math from eigen_face import eigenface

def file_abs_path(arg): return Path(os.path.realpath(arg)).parent

def img_show(imgs, H=None, W=None, info=None): imgs = np.asarray(imgs) assert imgs.ndim == 3 M = imgs.shape[0] if H is None: if W is None: H = int(math.sqrt(M)) W = math.ceil(M / H) else: H = math.ceil(M / W) else: if W is None: W = math.ceil(M / H) else: W = max(W, math.ceil(M / H))

plt.figure()
if info is not None:
    plt.suptitle(info)
for i in range(M):
    plt.subplot(H, W, i+1)
    plt.imshow(imgs[i], cmap='gray')
    plt.axis('off')

plt.show()

def load_images(): folder_path = file_abs_path(file) image_path = folder_path / 'orl_faces'

img_files = list(image_path.glob('**/*.pgm'))
print('There are {} images in {}'.format(len(img_files), image_path))
imgs = []
for img in img_files:
    img_tmp = Image.open(img)
    #img_tmp = img_tmp.resize((12, 9), Image.ANTIALIAS)    # 因为数据维度比较大,在调试的时候可以去掉这一行的注释,缩放一下图片,这样计算比较快。
    img_tmp = np.asarray(img_tmp, dtype=np.float32)
    imgs.append(img_tmp)

return np.asarray(imgs)

if name == 'main': imgs = load_images() # 加载图片,imgs的维度为MxHxW。即有M张图片,每一张高为H宽为W。 print(imgs.shape) img_show(imgs[::10], H=5, info='Raw face') # 展示原图 a, b = eigenface(imgs) # 获得特征值 a,特征向量 b.

num = 8
a = a[:num]
N, H, W = imgs.shape
b = b.T.reshape(H*W, H, W)
b = b[:num]
img_show(b, H=2, info='Eigenface')

</code></pre>


  • linalg.eig(mat)函数求得的特征值和特征向量已经按照从大到小排列了
  • np.shape() ; type() ; np.mat() ; np.asarray() ; np.mean(data,axis=?) ; mat.T
  • 最好不要用matrix格式,可能会数值溢出,最好转换成array处理
  • 图片等三维数组的理解,要有channel的概念 三维数组
  • 二维矩阵 三维矩阵之间转换☞用reshape函数
  • 三维矩阵变二维☞用flatten拉平