Eigen Faces

处理图像

一张 (H,W) 大小的图像可以按像素点展开为 (1,HW) 大小数组.

img1

我们将训练集中所有图像展开到一个 (N,HW) 大小的数组中;
然后求一个 (1,HW) 大小的平均脸

img2

参考代码:

# Suppose imgs is a (N, W, H) np array
img2D = imgs.reshape(imgs.shape[0],-1) # Flattern imgs to (N, WH)
img2D = img2D.astype("float32") # Set elem type to float
averageFace = np.mean(img2D, axis=0) # Calculate the average face

求特征脸 (Eigen Faces)

首先要声明, 上节中每个像素点(列)不是特征, 每个脸(行)才是特征.

用不恰当的话说, 我们要做的是找到最有特征的一组脸, 把每个脸当成一个维度, 构成一个高维空间;
然后把训练集中的所有脸 (不同人不同角度的照片) 映射到这个空间中, 形成一些点.

当有一张新的脸 (测试集) 出现, 我们把新的脸映射到空间中, 寻找与前面训练集里距离最近的点.

我们接下来就是要用 PCA (主成分分析) 求特征脸.

求每个特征 (每张脸) 的协方差矩阵

先将每张脸减去平均脸得到每张脸的差值 Diff_Face .

img3

Diff_FaceDiff_Face 的转置点乘得到一个 (HW,HW) 大小的矩阵, 再对矩阵中每个元素乘以 1HW1 就得到了协方差矩阵 Cov .

img4

按照 PCA 的方法, 接下来我们需要求 Cov 的特征值和特征向量.

但是这里有个问题, 就是我们手里的这个矩阵的维数太高了 (维数是 HW, 即每张图片的像素点个数);
直接求特征向量运算时间不可接受.

如果用来 PCA 分析的图片数量 (N, 也就是特征数量) 超过了像素数 (HW, 也就是行数), 那么可以选择不采用下面的方法.

Diff_Face 的转置点乘自己, 再对矩阵中每个元素乘以 1HW1 就得到了一个 (N,N) 的协方差矩阵 Cov'.

img5

可以证明, Cov' 的特征值与 Cov 的特征值相同;
Cov 的特征向量矩阵等于 Cov' 点乘 Diff_Face^T.

这里不要太过纠结于应该横着来还是竖着来, 可以参考一下我下面给出的代码.

最终我们得到的每个向量应该有 HW 个维度.

参考代码:

# Suppose that images2D is a (N, HW) np array, representing N images and each has HW pixels.
# Suppose that averageFace is a (1, HW) np array.
# Calculate the covariance matrix of the result mat
covMat = np.cov(images2D) # (N, N) matrix
# Calculate the eigenvalues and eigenvectors of the covariance matrix
# eigenValues is a (N, N) mat, eigenVecs is an 1D array with N elems
eigenValues, eigenVecs = np.linalg.eig(covMat)
# Calculate the engine faces of origin images
# Now eigenVecs is a (N, WH) mat
eigenVecs = np.dot(eigenVecs, images2D - averageFace)

PCA

上面求出了一维向量 eigenValues, 也就是 Cov 的特征值. 我们选取最大的前 K 个特征值, 找到他们的对应特征向量, 将这些向量正交化, 选为特征脸.

正交化后的向量组成了一个 (K,WH) 大小的矩阵, 表示构成了 K 维特征脸空间.

参考代码:

# Get the indexes of the K largest eigenvalues
indexes = np.argsort(eigenValues)[::-1][:K]
# Get the K largest eigenvalues
eigenValues = eigenValues[indexes].copy()
# Get the K largest eigenvectors, i.e., the engine faces
eigenVecs = eigenVecs[indexes].copy() # (N, HW) mat
# Orthogonalize the engine faces
orth_eigenVecs, _ = np.linalg.qr(eigenVecs.T)
orth_eigenVecs = orth_eigenVecs.T # (K, HW) mat

训练样本

假设有 N 张图片作为训练集, 存放在一个 (N,HW) 大小的数组 trainImgs 中; 还有一个 (N,1) 大小的数组 labels 表示每张图片属于第几组(或者说第几个人).
averageFace(1,HW) 大小的平均脸, 求法上文已给出.
orth_eigenVecs(K,HW) 大小的数组, 是特征脸, 求法上文已给出.

现在我们来训练样本.

# reshape faceImgs to [N, (H * W)]
trainImgs = trainImgs.reshape(trainImgs.shape[0], -1)
# reshape averageFace to [1, (H * W)]
averageFace = averageFace.reshape(1, -1)
# Subtract averageFace from faceImgs
trainImgs -= averageFace
# Calculate the engine values of the train faces
engineValues = np.dot(trainImgs, orth_eigenVecs.T) # [N, K]
labels = labels.reshape(-1,1)
trainedData = np.concatenate((engineValues, labels), axis=1)

trainedData 是一个 (N,K+1) 大小的数组.

K 列存放了每张图片映射到特征脸空间后在每个 kK 维度下的投影值. (或者我们可以说, 每行表示一个点, 前 K 列表示出了这个点在我们的 K 维特征脸空间中的坐标)
最后一列是传入的数据标签, 也就是说这个图像属于第一个人还是第十个人.

预测

我们有 N 个训练样本, 上面最后算出的 trainedData 标出每个点的坐标.

那我们接下来要做的显然是:
给出一个待预测图像, 用同样的方法算出其在特征脸空间中的坐标, 然后和 trainedData 中的 N 个坐标比较, 找到距离最近的那个点.
那个点的标签, 应该就是待预测图像的标签.

假设 testFace 为待预测图像, 大小为 (1,HW).
trainedData 是一个 (N,K+1) 大小的数组, 表示 N 个已训练的图像在特征脸空间中的坐标, 同时每个点的标签存放在 (1,N) 大小的数组 labels 中.
averageFace(1,HW) 大小的平均脸, 求法上文已给出.
orth_eigenVecs(K,HW) 大小的数组, 是特征脸, 求法上文已给出.

# reshape testFace to [1 x (H * W)]
testFace = testFace.reshape(1, -1)
# Subtract averageFace from testFace
testFace -= averageFace
# Calculate the engine value of the test face
testEngineValue = np.dot(testFace, orth_engineVecs.T)
# Calculate the distance between the test face and the train faces
distances = np.linalg.norm(engineValues - testEngineValue, axis=1)
# Get the index of the train face with the minimum distance
index = np.argmin(distances)
# Get the label of the train face with the minimum distance
label = labels[index]

label 就是最终结果.

本文作者:jamesnulliu

本文链接:https://www.cnblogs.com/jamesnulliu/p/17338495.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   JamesNULLiu  阅读(39)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起