原文地址:
http://ihoge.cn/2018/PCA+SVM人脸识别.html
加载数据
这里使用的测试数据共包含40位人员照片,每个人10张照片。也可登陆http://www.cl.cam.ac.uk/research/dtg/attarchive/facesataglance.html 查看400张照片的缩略图。
import time
import logging
from sklearn.datasets import fetch_olivetti_faces
logging.basicConfig(level = logging.INFO, format="%(asctime)s %(message)s") # 这里INFO必须大写
data_home = 'code/datasets/'
logging.info("开始加载数据")
faces = fetch_olivetti_faces(data_home=data_home)
logging.info("加载完成")
这里做下简单的解释:
加载的图片保存在faces变量里,sklaern已经把每张照片处理成剪切掉头发部分并且64x64大小且人脸居中显示。在真实生产环境中这一步很重要,否则模型将被大量的噪声干扰(即照片背景,变化的发型等,这些特征都应该排除在输入特征之外)。最后要成功下载数据集还需要安装Python图片图里工具Pillow否则无法对图片解码。下面输出下数据的概要信息:
import numpy as np
X = faces.data
y = faces.target
targets = np.unique(faces.target)
target_names = np.array(["p%d" % t for t in targets]) #给每个人做标签
n_targets = target_name.shape[0]
n_samples, h, w = faces.images.shape
print('Samples count:{}\nTarget count:{}'.format(n_samples, n_targets))
print('Image size:{}x{}\nData shape:{}'.format(w, h, X.shape))
Samples count:400
Target count:40
Image size:64x64
Data shape:(400, 4096)
由输出可知,共有40人,照片总量400,输入特征(64x64=4096)个。
为了直观观察数据,从每个人物的照片里随机选择一张显示,定义下画图工具:
其中输入参数images是一个二维数据,每一行都是一个图片数据。在加载数据时,fech_ollivetti_faces()函数已经自动做了预处理,图片的每个像素的RBG值都转换成了[0,1]浮点数。因此,画出来的照片也是黑白的。子图片识别领域一般用黑白照片就可以了,减少计算量的同时也更加准确。
%matplotlib inline
from matplotlib import pyplot as plt
def plot_gallery(images, titles, h, w, n_row=2, n_col=5):
# 显示图片阵列:
plt.figure(figsize=(2*n_col, 2.2*n_row),dpi=140)
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.01)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i+1)
plt.imshow(images[i].reshape((h,w)), cmap=plt.cm.gray)
plt.title(titles[i])
plt.axis('off')
n_row = 2
n_col = 6
sample_images = None
sample_titles = []
for i in range(n_targets):
people_images = X[y==i] # 注意这里传入i
people_sample_index = np.random.randint(0, people_images.shape[0], 1)
people_sample_image = people_images[people_sample_index, :]
if sample_images is not None:
sample_images = np.concatenate((sample_images, people_sample_image), axis=0)
else:
sample_images =people_sample_image
sample_titles.append(target_names[i]) # 这里target_names是在前面生成的标签
plot_gallery(sample_images, sample_titles, h, w, n_row, n_col)
#代码中X[y=i]可以选择除特定的所有照片,随机选出来的照片放在sample.images数组对象里,最后调用之前定义的函数把照片画出来。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=4)
支持向量机第一次尝试
直接食用支持向量机来实现人脸识别:
from time import time
from sklearn.svm import SVC
t = time()
clf = SVC(class_weight='balanced')
clf.fit(X_train, y_train)
print("耗时:{}秒".format(time() - t))
耗时:1.0220119953155518秒
1、接着对人脸数据进行预测:使用confusion_matrix
查看准确性:
from sklearn.metrics import confusion_matrix
y_pred = clf.predict(X_test)
cm = confusion_matrix(y_test, y_pred, labels=range(n_targets))
print("confusion_matrix:\n")
# np.set_printoptions(threshold=np.nan)
print(cm[:10])
confusion_matrix:
[[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
上面np.set_printoptions()
是为了确保cm完整输出,这是因为这个数组是40x40的,默认情况下不会全部输出。??
2、使用classification_report
查看准确性
但是很明显输出结果效果很差。 因为confusion_matrix
理想的输出是矩阵的对角线上有数组,其他地方都为0,而且这里很多图片都被预测成索引为12的类别了。我买再来看下classification_report
的结果:
from sklearn.metrics import classif