import numpy as np
import cv2
import os
from sklearn.decomposition import PCA
from sklearn.metrics import pairwise_distances
def load_images_from_folder(folder_path, img_size=(100, 100)):
"""读取文件夹中的所有图像,将其灰度化、统一尺寸并向量化。"""
images = []
labels = []
for label_dir in os.listdir(folder_path):
person_path = os.path.join(folder_path, label_dir)
if not os.path.isdir(person_path):
continue
for img_name in os.listdir(person_path):
img_path = os.path.join(person_path, img_name)
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
img_resized = cv2.resize(img, img_size)
images.append(img_resized.flatten())
labels.append(int(label_dir))
return np.array(images), np.array(labels)
def train_pca_face_recognizer(X_train, n_components=100):
"""训练 PCA 模型,并返回均值脸和特征向量。"""
pca = PCA(n_components=n_components, svd_solver='randomized', whiten=True).fit(X_train)
mean_face = pca.mean_
eigenfaces = pca.components_
return pca, mean_face, eigenfaces
def project_face(pca, face):
"""将人脸投影到特征空间"""
return pca.transform(face.reshape(1, -1))
def recognize_face(projected_test_face, projected_train_faces, train_labels):
"""通过计算欧氏距离进行最近邻匹配。返回识别标签和置信度(距离)。"""
distances = pairwise_distances(projected_test_face, projected_train_faces, metric='euclidean')
min_index = np.argmin(distances)
return train_labels[min_index], distances[0, min_index]
if __name__ == "__main__":
train_folder = "path/to/olivetti/train"
test_folder = "path/to/olivetti/test"
X_train, y_train = load_images_from_folder(train_folder)
X_test, y_test = load_images_from_folder(test_folder)
n_components = 100
pca, mean_face, eigenfaces = train_pca_face_recognizer(X_train, n_components)
projected_train = pca.transform(X_train)
correct = 0
for i, test_face in enumerate(X_test):
proj_test = project_face(pca, test_face)
pred_label, confidence = recognize_face(proj_test, projected_train, y_train)
print(f"真实标签:{y_test[i]}, 预测标签:{pred_label}, 置信度:{confidence:.2f}")
if pred_label == y_test[i]:
correct += 1
accuracy = correct / len(X_test)
print(f"\n识别准确率:{accuracy * 100:.2f}%")
import matplotlib.pyplot as plt
def plot_eigenfaces(eigenfaces, img_shape=(100, 100), n_row=5, n_col=5):
plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
plt.suptitle("Eigenfaces (前 25 个特征脸)", fontsize=16)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(eigenfaces[i].reshape(img_shape), cmap='gray')
plt.title(f"特征脸 {i+1}")
plt.xticks([])
plt.yticks([])
plt.show()
plot_eigenfaces(pca.components_, img_shape=(100, 100), n_row=5, n_col=5)