Python机器学习人脸识别系统:从期末大作业到门禁机实战

发布时间:2026/10/12 19:05:27
Python机器学习人脸识别系统:从期末大作业到门禁机实战
简介这份资源是面向高校学生与Python初学者的机器学习人脸识别系统完整项目包可直接用于期末大作业、课程设计或自学练手。压缩包共4个文件包含2个py源码文件、1份pdf报告文档和1份md说明文件整体约631KB体积轻便易于部署。其中主程序与分类模块分工明确代码附有注释新手也能看懂运行逻辑pdf报告则完整呈现了人脸性别识别大作业的设计思路与实现过程可直接参考撰写实验报告。目前已有283人学习下载说明其在同类作业资源中具有一定认可度。读者拿到后既能获得可运行的识别系统源码也能借助报告文档理解机器学习在人脸识别中的落地流程适合需要快速完成课程任务或积累项目经验的同学参考使用。1. 从一份期末大作业说起机器学习人脸识别系统到底交付了什么每年到了期末季总有一批同学在深夜对着「人脸识别系统」这几个字发愁。标题里这份「Python期末大作业基于机器学习的人脸识别系统源码报告文档」本质上是一个完整的课程设计交付物一套能跑起来的 Python 代码加上一份讲清楚原理和实验过程的报告。它要解决的问题很具体——给定若干人的照片训练一个模型让它能认出镜头前是谁。适合谁正在做机器学习、模式识别、计算机视觉课程设计的学生以及想用一个小项目把「数据预处理→特征提取→模型训练→推理部署」这条链路走通的新手。人脸识别门禁机这类产品听起来高大上但拆开看核心流程和一份期末作业没有本质区别区别只在数据规模和工程细节。这一章先把这套系统讲清楚后面几章带你从零复现再讲清楚哪里最容易翻车。2. 人脸识别系统的技术选型为什么是机器学习而不是深度学习2.1 课程作业场景下的三条技术路线对比在动手之前先想清楚用哪条路线。人脸识别从技术演进看大致分三代早期基于几何特征和模板匹配中期基于传统机器学习如 PCA、LDA、SVM近期基于深度卷积网络如 FaceNet、ArcFace。期末大作业这个场景选型不能只看精度还要看算力、数据量、可解释性和报告好不好写。路线代表方法数据需求训练算力报告可写性适合场景传统机器学习PCASVM、LDA每人 10~20 张即可CPU 可跑原理清晰公式好推导课程作业、小样本轻量深度学习小型 CNN每人 50 张以上需要 GPU 或较长时间网络结构可画图有显卡的进阶作业预训练模型微调ArcFace、FaceNet每人 5 张即可推理需 GPU 更佳偏工程原理难自证追求高精度的项目我一般会建议如果报告要求你推导原理、画特征脸、讲清楚数学过程选 PCALDASVM 这条传统机器学习路线如果只是要求系统能跑、精度够看可以用预训练模型做特征提取再套一个分类器。标题里写的是「机器学习」不是「深度学习」所以本文主线走传统机器学习路线这也是最稳妥、最容易复现的选择。2.2 最小可运行环境搭建环境是第一个坑。Python 版本、库版本不匹配能让你在第一步就卡住。下面这套组合是我在多个课程作业里验证过能跑通的。# 建议 Python 3.8 ~ 3.10太新的版本部分库轮子不全 python -m venv face_env # Windows 激活 face_env\Scripts\activate # Linux / macOS 激活 source face_env/bin/activate # 核心依赖指定版本避免踩坑 pip install numpy1.24.3 pip install opencv-python4.8.1.78 pip install scikit-learn1.3.0 pip install matplotlib3.7.2 pip install pillow10.0.0逻辑说明用虚拟环境隔离依赖避免污染系统 Python。numpy 是数值计算底座opencv 负责图像读取和人脸检测scikit-learn 提供 PCA、LDA、SVM 等算法matplotlib 用来画图写报告。参数说明numpy 不要装 2.x部分老代码会报np.float已移除opencv 用opencv-python而不是opencv-contrib-python除非你要用额外的人脸模块。安装 numpy 库的方法如果报错优先检查 pip 是否升级到最新python -m pip install --upgrade pip。提示如果下载慢换国内镜像源命令末尾加-i https://pypi.tuna.tsinghua.edu.cn/simple不要用来源不明的第三方包。2.3 数据集的组织方式数据组织决定了后面代码好不好写。常见做法是按人分文件夹每个文件夹放这个人的多张照片文件夹名就是标签。dataset/ ├── person_01/ │ ├── 001.jpg │ ├── 002.jpg │ └── ... ├── person_02/ │ ├── 001.jpg │ └── ... └── person_03/ └── ...每人类别建议不少于 10 张总数不少于 100 张否则 PCA 降维后特征不稳定。照片要求正脸、光照均匀、分辨率不低于 100x100。如果用人脸识别门禁机的真实场景数据还要考虑侧脸和遮挡但课程作业阶段先用规整数据把流程跑通。3. 从原始照片到特征向量数据预处理与 PCA 降维实操3.1 人脸检测与对齐的最小代码原始照片往往背景杂乱直接送进模型会引入大量噪声。第一步是用 OpenCV 的 Haar 级联检测器把人脸框出来再统一缩放到固定尺寸。import cv2 import os import numpy as np # 加载 OpenCV 自带的人脸检测器 face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) def detect_and_crop(img_path, size(100, 100)): img cv2.imread(img_path) if img is None: return None gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # scaleFactor 和 minNeighbors 是两个关键参数 faces face_cascade.detectMultiScale( gray, scaleFactor1.1, minNeighbors5, minSize(60, 60) ) if len(faces) 0: return None # 取面积最大的那张脸避免误检 x, y, w, h max(faces, keylambda f: f[2] * f[3]) face gray[y:yh, x:xw] face cv2.resize(face, size) # 直方图均衡化缓解光照影响 face cv2.equalizeHist(face) return face逻辑说明detectMultiScale返回所有人脸框取面积最大的一个作为主脸。scaleFactor1.1表示每次缩放比例越小检测越细但越慢minNeighbors5控制误检值越大越严格但可能漏检。equalizeHist做直方图均衡化这一步对光照不均的照片提升明显。参数说明minSize设成 60x60 可以过滤掉远处的小脸误检如果照片里人脸很大可以适当调大。3.2 构建特征矩阵与标签向量把每张照片处理成人脸图像后拉平成向量堆成矩阵。这一步是传统机器学习人脸识别的核心数据结构。def build_dataset(root_dir, size(100, 100)): X, y [], [] label_map {} current_label 0 for person_name in sorted(os.listdir(root_dir)): person_dir os.path.join(root_dir, person_name) if not os.path.isdir(person_dir): continue label_map[current_label] person_name for fname in os.listdir(person_dir): if not fname.lower().endswith((.jpg, .png, .jpeg)): continue face detect_and_crop(os.path.join(person_dir, fname), size) if face is None: continue # 拉平成 10000 维向量 X.append(face.flatten().astype(np.float32)) y.append(current_label) current_label 1 return np.array(X), np.array(y), label_map逻辑说明flatten()把 100x100 的图像变成 10000 维向量这是 PCA 的输入。label_map保存标签到人名的映射推理时用来输出名字。参数说明如果检测失败的照片较多说明数据质量差需要人工筛一遍size不要设太小50x50 以下会丢失辨识特征。3.3 PCA 降维把 10000 维压到 100 维10000 维直接训练样本数往往只有几百维度灾难会让模型完全失效。PCA 的作用是找到方差最大的方向把维度压下来。from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler # X 是 build_dataset 返回的特征矩阵 scaler StandardScaler() X_scaled scaler.fit_transform(X) # n_components 可以设成整数保留多少维或小数保留多少方差 pca PCA(n_components0.95, whitenTrue) X_pca pca.fit_transform(X_scaled) print(f原始维度: {X.shape[1]}, 降维后: {X_pca.shape[1]})逻辑说明先标准化再 PCA避免某些像素值域差异影响主成分方向。n_components0.95表示保留 95% 的方差具体降到多少维由数据决定通常几百张图会降到 50~150 维。whitenTrue让各主成分方差归一对后续 SVM 有帮助。参数说明如果报告要求固定维度把n_components改成整数如 100如果降维后精度反而下降检查是否漏了标准化。注意PCA 必须在训练集上 fit再 transform 测试集。如果全量数据一起 fit会造成数据泄露报告里的精度虚高答辩时容易被问穿。4. 分类器训练与推理SVM、LDA 怎么选怎么调4.1 用 SVM 做多分类的完整流程PCA 降维后接一个分类器。SVM 在小样本高维数据上表现稳定是课程作业的常见选择。from sklearn.svm import SVC from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import classification_report, accuracy_score # 划分训练集和测试集stratify 保证每类比例一致 X_train, X_test, y_train, y_test train_test_split( X_pca, y, test_size0.25, random_state42, stratifyy ) # 网格搜索找最优参数 param_grid { C: [0.1, 1, 10, 100], gamma: [scale, 0.001, 0.01, 0.1], kernel: [rbf, linear] } grid GridSearchCV(SVC(probabilityTrue), param_grid, cv5, n_jobs-1) grid.fit(X_train, y_train) print(最优参数:, grid.best_params_) best_svm grid.best_estimator_ y_pred best_svm.predict(X_test) print(准确率:, accuracy_score(y_test, y_pred)) print(classification_report(y_test, y_pred))逻辑说明stratifyy保证训练测试集里每类样本比例一致避免某类全进训练集。GridSearchCV用 5 折交叉验证遍历参数组合n_jobs-1用满 CPU。参数说明C越大对误分类惩罚越重容易过拟合gamma控制 RBF 核的影响范围越大越容易过拟合。kernellinear在样本数远小于维度时可能更稳。如果准确率低于 80%先检查数据预处理再调参数。4.2 LDA 做特征降维加分类LDA 和 PCA 的区别PCA 找方差最大方向无监督LDA 找类间距离大、类内距离小的方向有监督。人脸识别里 LDA 往往比 PCA 更适合分类。from sklearn.discriminant_analysis import LinearDiscriminantAnalysis # LDA 降维的维度上限是 类别数 - 1 n_classes len(np.unique(y)) lda LinearDiscriminantAnalysis(n_componentsmin(n_classes - 1, 50)) X_lda lda.fit_transform(X_scaled, y) # 再用简单分类器 X_train, X_test, y_train, y_test train_test_split( X_lda, y, test_size0.25, random_state42, stratifyy ) clf SVC(kernellinear, C1.0) clf.fit(X_train, y_train) print(LDASVM 准确率:, clf.score(X_test, y_test))逻辑说明LDA 降维必须传入标签y这是它和 PCA 的本质区别。n_components最大只能是类别数减一比如 10 个人最多降到 9 维。参数说明如果类别数很少比如 5 个人LDA 降到 4 维可能损失信息可以先用 PCA 降到 100 维再用 LDA。常见做法是 PCALDA 串联先无监督降噪再有监督降维。4.3 推理阶段从摄像头到识别结果训练完模型要能实际用。下面是一个从单张图片推理的完整函数。import joblib # 保存模型 joblib.dump({pca: pca, scaler: scaler, svm: best_svm, label_map: label_map}, face_model.pkl) def predict_face(img_path, model_pathface_model.pkl): bundle joblib.load(model_path) face detect_and_crop(img_path) if face is None: return 未检测到人脸 vec face.flatten().astype(np.float32).reshape(1, -1) vec bundle[scaler].transform(vec) vec bundle[pca].transform(vec) pred bundle[svm].predict(vec)[0] prob bundle[svm].predict_proba(vec).max() name bundle[label_map][pred] return f{name} (置信度 {prob:.2f})逻辑说明推理时的预处理必须和训练时完全一致顺序是检测→缩放→均衡化→拉平→标准化→PCA→分类。任何一步不一致结果都会错得离谱。参数说明predict_proba给出置信度低于 0.6 建议判为未知避免强行归类。如果部署到人脸识别门禁机场景还要加活体检测但课程作业阶段可以省略。5. 避坑与排查人脸识别作业最容易翻车的五个地方5.1 准确率虚高到 99% 但实际不能用现象测试集准确率 99%但换一张新照片就认错。原因训练集和测试集划分时没有按人划分同一个人既在训练集又在测试集模型只是记住了这张脸。解决用GroupShuffleSplit按人划分或者确保测试集里的人不在训练集出现。课程作业里如果要求「识别已知的人」可以按样本划分但报告里要写清楚。5.2 检测不到人脸或框错位置现象detectMultiScale返回空列表或者框到背景。原因Haar 检测器对侧脸、暗光、遮挡很敏感参数不合适。解决调小scaleFactor到 1.05调大minNeighbors到 6加minSize限制。如果还是不行换 DNN 人脸检测器OpenCV 自带cv2.dnn模块精度高很多但需要下载模型文件。5.3 PCA 降维后维度还是很高现象n_components0.95降完还有 800 维。原因图像像素间相关性低方差分散95% 方差需要很多主成分。解决先把图像缩小到 50x50或者改用n_components100固定维度。也可以先做 PCA 再 LDALDA 能把维度压到类别数减一。5.4 内存溢出或训练极慢现象几千张图训练时内存爆掉。原因10000 维浮点矩阵几千张就是几百 MBPCA 计算协方差矩阵更吃内存。解决用PCA(svd_solverrandomized)加速或者分批读取数据。图像尺寸降到 80x80 能省近一半内存。5.5 报告里的公式和代码对不上现象报告写 PCA 用协方差矩阵特征分解代码用 sklearn 的svd_solver。原因sklearn 默认用 SVD 实现 PCA和教科书上的特征分解数学等价但数值更稳。解决报告里说明「采用 SVD 实现与特征分解等价」或者手动用np.linalg.eigh实现一遍对照。答辩时老师问起能讲清楚两者关系就是加分项。6. 让作业再上一个台阶交叉验证与混淆矩阵的写法前面把系统跑通了但如果想让报告更有说服力光有一个准确率数字不够。我一般会补两样东西交叉验证的稳定性分析和混淆矩阵的可视化。交叉验证能说明模型不是靠某一次划分走运混淆矩阵能暴露哪些人容易被认错。from sklearn.model_selection import cross_val_score, StratifiedKFold from sklearn.metrics import confusion_matrix import matplotlib.pyplot as plt import seaborn as sns # 5 折交叉验证看准确率波动 cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(best_svm, X_pca, y, cvcv, scoringaccuracy) print(f交叉验证准确率: {scores.mean():.3f} ± {scores.std():.3f}) # 混淆矩阵 cm confusion_matrix(y_test, y_pred) plt.figure(figsize(8, 6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabels[label_map[i] for i in range(len(label_map))], yticklabels[label_map[i] for i in range(len(label_map))]) plt.xlabel(预测标签) plt.ylabel(真实标签) plt.title(人脸识别混淆矩阵) plt.tight_layout() plt.savefig(confusion_matrix.png, dpi150)逻辑说明cross_val_score返回 5 次划分的准确率均值反映整体水平标准差反映稳定性。标准差大于 0.05 说明数据划分影响大需要检查样本是否均衡。混淆矩阵对角线是正确分类非对角线是错分如果某两列数值特别高说明这两个人特征相似可以考虑增加这两人的训练样本。参数说明StratifiedKFold保证每折里类别比例一致比普通 KFold 更适合分类任务。还有一个技巧把 PCA 降维后的前两个主成分画散点图能直观看到类别是否可分。如果散点图里各类混在一起说明 PCA 降维丢了判别信息应该换 LDA 或者增加数据。这个图放进报告比干巴巴的数字有说服力得多。最后说个血泪经验我见过太多人把代码跑通就交差报告里只贴结果不写过程。其实老师看的是你有没有理解每一步在干什么。把预处理前后的对比图、PCA 保留方差曲线、不同参数的准确率对比表放进去工作量看起来扎实分数自然高。这套流程走下来从数据到模型到评估完整闭环换成真实的人脸识别门禁机场景要补的只是活体检测和工程部署核心逻辑一模一样。希望帮到你。本文还有配套的精品资源点击获取